"Fossies" - the Fresh Open Source Software Archive

Member "neutron-14.0.3/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_dvr_neutron_agent.py" (22 Oct 2019, 31667 Bytes) of package /linux/misc/openstack/neutron-14.0.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "ovs_dvr_neutron_agent.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.0.2_vs_14.0.3.

    1 # Copyright 2014, Hewlett-Packard Development Company, L.P.
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 
   16 import sys
   17 
   18 import netaddr
   19 from neutron_lib import constants as n_const
   20 from oslo_log import log as logging
   21 import oslo_messaging
   22 from oslo_utils import excutils
   23 from osprofiler import profiler
   24 
   25 from neutron.common import utils as n_utils
   26 from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants
   27 
   28 LOG = logging.getLogger(__name__)
   29 
   30 
   31 # A class to represent a DVR-hosted subnet including vif_ports resident on
   32 # that subnet
   33 class LocalDVRSubnetMapping(object):
   34     def __init__(self, subnet, csnat_ofport=constants.OFPORT_INVALID):
   35         # set of compute ports on this dvr subnet
   36         self.compute_ports = {}
   37         self.subnet = subnet
   38         self.csnat_ofport = csnat_ofport
   39         self.dvr_owned = False
   40 
   41     def __str__(self):
   42         return ("subnet = %s compute_ports = %s csnat_port = %s"
   43                 " is_dvr_owned = %s" %
   44                 (self.subnet, self.get_compute_ofports(),
   45                  self.get_csnat_ofport(), self.is_dvr_owned()))
   46 
   47     def get_subnet_info(self):
   48         return self.subnet
   49 
   50     def set_dvr_owned(self, owned):
   51         self.dvr_owned = owned
   52 
   53     def is_dvr_owned(self):
   54         return self.dvr_owned
   55 
   56     def add_compute_ofport(self, vif_id, ofport):
   57         self.compute_ports[vif_id] = ofport
   58 
   59     def remove_compute_ofport(self, vif_id):
   60         self.compute_ports.pop(vif_id, 0)
   61 
   62     def remove_all_compute_ofports(self):
   63         self.compute_ports.clear()
   64 
   65     def get_compute_ofports(self):
   66         return self.compute_ports
   67 
   68     def set_csnat_ofport(self, ofport):
   69         self.csnat_ofport = ofport
   70 
   71     def get_csnat_ofport(self):
   72         return self.csnat_ofport
   73 
   74 
   75 class OVSPort(object):
   76     def __init__(self, id, ofport, mac, device_owner):
   77         self.id = id
   78         self.mac = mac
   79         self.ofport = ofport
   80         self.subnets = set()
   81         self.device_owner = device_owner
   82 
   83     def __str__(self):
   84         return ("OVSPort: id = %s, ofport = %s, mac = %s, "
   85                 "device_owner = %s, subnets = %s" %
   86                 (self.id, self.ofport, self.mac,
   87                  self.device_owner, self.subnets))
   88 
   89     def add_subnet(self, subnet_id):
   90         self.subnets.add(subnet_id)
   91 
   92     def remove_subnet(self, subnet_id):
   93         self.subnets.remove(subnet_id)
   94 
   95     def remove_all_subnets(self):
   96         self.subnets.clear()
   97 
   98     def get_subnets(self):
   99         return self.subnets
  100 
  101     def get_device_owner(self):
  102         return self.device_owner
  103 
  104     def get_mac(self):
  105         return self.mac
  106 
  107     def get_ofport(self):
  108         return self.ofport
  109 
  110 
  111 @profiler.trace_cls("ovs_dvr_agent")
  112 class OVSDVRNeutronAgent(object):
  113     '''Implements OVS-based DVR (Distributed Virtual Router) agent'''
  114     # history
  115     #   1.0 Initial version
  116 
  117     def __init__(self, context, plugin_rpc, integ_br, tun_br,
  118                  bridge_mappings, phys_brs, int_ofports, phys_ofports,
  119                  patch_int_ofport=constants.OFPORT_INVALID,
  120                  patch_tun_ofport=constants.OFPORT_INVALID,
  121                  host=None, enable_tunneling=False,
  122                  enable_distributed_routing=False,
  123                  arp_responder_enabled=False):
  124         self.context = context
  125         self.plugin_rpc = plugin_rpc
  126         self.host = host
  127         self.enable_tunneling = enable_tunneling
  128         self.enable_distributed_routing = enable_distributed_routing
  129         self.bridge_mappings = bridge_mappings
  130         self.phys_brs = phys_brs
  131         self.int_ofports = int_ofports
  132         self.phys_ofports = phys_ofports
  133         self.reset_ovs_parameters(integ_br, tun_br,
  134                                   patch_int_ofport, patch_tun_ofport)
  135         self.reset_dvr_parameters()
  136         self.dvr_mac_address = None
  137         self.arp_responder_enabled = arp_responder_enabled
  138         if self.enable_distributed_routing:
  139             self.get_dvr_mac_address()
  140 
  141     def setup_dvr_flows(self):
  142         self.setup_dvr_flows_on_integ_br()
  143         self.setup_dvr_flows_on_tun_br()
  144         self.setup_dvr_flows_on_phys_br()
  145         self.setup_dvr_mac_flows_on_all_brs()
  146 
  147     def reset_ovs_parameters(self, integ_br, tun_br,
  148                              patch_int_ofport, patch_tun_ofport):
  149         '''Reset the openvswitch parameters'''
  150         self.int_br = integ_br
  151         self.tun_br = tun_br
  152         self.patch_int_ofport = patch_int_ofport
  153         self.patch_tun_ofport = patch_tun_ofport
  154 
  155     def reset_dvr_parameters(self):
  156         '''Reset the DVR parameters'''
  157         self.local_dvr_map = {}
  158         self.local_csnat_map = {}
  159         self.local_ports = {}
  160         self.registered_dvr_macs = set()
  161 
  162     def get_dvr_mac_address(self):
  163         try:
  164             self.get_dvr_mac_address_with_retry()
  165         except oslo_messaging.RemoteError as e:
  166             LOG.error('L2 agent could not get DVR MAC address at '
  167                       'startup due to RPC error.  It happens when the '
  168                       'server does not support this RPC API.  Detailed '
  169                       'message: %s', e)
  170         except oslo_messaging.MessagingTimeout:
  171             LOG.error('DVR: Failed to obtain a valid local '
  172                       'DVR MAC address')
  173 
  174         if not self.in_distributed_mode():
  175             sys.exit(1)
  176 
  177     def get_dvr_mac_address_with_retry(self):
  178         # Get the local DVR MAC Address from the Neutron Server.
  179         # This is the first place where we contact the server on startup
  180         # so retry in case it's not ready to respond
  181         for retry_count in reversed(range(5)):
  182             try:
  183                 details = self.plugin_rpc.get_dvr_mac_address_by_host(
  184                     self.context, self.host)
  185             except oslo_messaging.MessagingTimeout as e:
  186                 with excutils.save_and_reraise_exception() as ctx:
  187                     if retry_count > 0:
  188                         ctx.reraise = False
  189                         LOG.warning('L2 agent could not get DVR MAC '
  190                                     'address from server. Retrying. '
  191                                     'Detailed message: %s', e)
  192             else:
  193                 LOG.debug("L2 Agent DVR: Received response for "
  194                           "get_dvr_mac_address_by_host() from "
  195                           "plugin: %r", details)
  196                 self.dvr_mac_address = (
  197                     netaddr.EUI(details['mac_address'],
  198                                 dialect=netaddr.mac_unix_expanded))
  199                 return
  200 
  201     def setup_dvr_flows_on_integ_br(self):
  202         '''Setup up initial dvr flows into br-int'''
  203 
  204         LOG.info("L2 Agent operating in DVR Mode with MAC %s",
  205                  self.dvr_mac_address)
  206         # Add a canary flow to int_br to track OVS restarts
  207         self.int_br.setup_canary_table()
  208 
  209         # Insert 'drop' action as the default for Table DVR_TO_SRC_MAC
  210         self.int_br.install_drop(table_id=constants.DVR_TO_SRC_MAC, priority=1)
  211 
  212         self.int_br.install_drop(table_id=constants.DVR_TO_SRC_MAC_VLAN,
  213                                  priority=1)
  214 
  215         for physical_network in self.bridge_mappings:
  216             self.int_br.install_drop(table_id=constants.LOCAL_SWITCHING,
  217                                      priority=2,
  218                                      in_port=self.int_ofports[
  219                                          physical_network])
  220 
  221     def setup_dvr_flows_on_tun_br(self):
  222         '''Setup up initial dvr flows into br-tun'''
  223         if not self.enable_tunneling:
  224             return
  225 
  226         self.tun_br.install_goto(dest_table_id=constants.DVR_PROCESS,
  227                                  priority=1,
  228                                  in_port=self.patch_int_ofport)
  229 
  230         # table-miss should be sent to learning table
  231         self.tun_br.install_goto(table_id=constants.DVR_NOT_LEARN,
  232                                  dest_table_id=constants.LEARN_FROM_TUN)
  233 
  234         self.tun_br.install_goto(table_id=constants.DVR_PROCESS,
  235                                  dest_table_id=constants.PATCH_LV_TO_TUN)
  236 
  237     def setup_dvr_flows_on_phys_br(self):
  238         '''Setup up initial dvr flows into br-phys'''
  239 
  240         for physical_network in self.bridge_mappings:
  241             self.phys_brs[physical_network].install_goto(
  242                 in_port=self.phys_ofports[physical_network],
  243                 priority=2,
  244                 dest_table_id=constants.DVR_PROCESS_VLAN)
  245             self.phys_brs[physical_network].install_goto(
  246                 priority=1,
  247                 dest_table_id=constants.DVR_NOT_LEARN_VLAN)
  248             self.phys_brs[physical_network].install_goto(
  249                 table_id=constants.DVR_PROCESS_VLAN,
  250                 priority=0,
  251                 dest_table_id=constants.LOCAL_VLAN_TRANSLATION)
  252             self.phys_brs[physical_network].install_drop(
  253                 table_id=constants.LOCAL_VLAN_TRANSLATION,
  254                 in_port=self.phys_ofports[physical_network],
  255                 priority=2)
  256             self.phys_brs[physical_network].install_normal(
  257                 table_id=constants.DVR_NOT_LEARN_VLAN,
  258                 priority=1)
  259 
  260     def _add_dvr_mac_for_phys_br(self, physical_network, mac):
  261         self.int_br.add_dvr_mac_vlan(mac=mac,
  262                                      port=self.int_ofports[physical_network])
  263         phys_br = self.phys_brs[physical_network]
  264         phys_br.add_dvr_mac_vlan(mac=mac,
  265                                  port=self.phys_ofports[physical_network])
  266 
  267     def _add_arp_dvr_mac_for_phys_br(self, physical_network, mac):
  268         self.int_br.add_dvr_gateway_mac_arp_vlan(
  269                 mac=mac, port=self.int_ofports[physical_network])
  270 
  271     def _remove_dvr_mac_for_phys_br(self, physical_network, mac):
  272         # REVISIT(yamamoto): match in_port as well?
  273         self.int_br.remove_dvr_mac_vlan(mac=mac)
  274         phys_br = self.phys_brs[physical_network]
  275         # REVISIT(yamamoto): match in_port as well?
  276         phys_br.remove_dvr_mac_vlan(mac=mac)
  277 
  278     def _add_dvr_mac_for_tun_br(self, mac):
  279         self.int_br.add_dvr_mac_tun(mac=mac, port=self.patch_tun_ofport)
  280         self.tun_br.add_dvr_mac_tun(mac=mac, port=self.patch_int_ofport)
  281 
  282     def _add_arp_dvr_mac_for_tun_br(self, mac):
  283         self.int_br.add_dvr_gateway_mac_arp_tun(
  284                 mac=mac, port=self.patch_tun_ofport)
  285 
  286     def _remove_dvr_mac_for_tun_br(self, mac):
  287         self.int_br.remove_dvr_mac_tun(mac=mac, port=self.patch_tun_ofport)
  288         # REVISIT(yamamoto): match in_port as well?
  289         self.tun_br.remove_dvr_mac_tun(mac=mac)
  290 
  291     def _add_dvr_mac(self, mac):
  292         for physical_network in self.bridge_mappings:
  293             self._add_dvr_mac_for_phys_br(physical_network, mac)
  294         if self.enable_tunneling:
  295             self._add_dvr_mac_for_tun_br(mac)
  296         LOG.debug("Added DVR MAC flow for %s", mac)
  297         self.registered_dvr_macs.add(mac)
  298 
  299     def _add_dvr_mac_for_arp(self, mac):
  300         for physical_network in self.bridge_mappings:
  301             self._add_arp_dvr_mac_for_phys_br(physical_network, mac)
  302         if self.enable_tunneling:
  303             self._add_arp_dvr_mac_for_tun_br(mac)
  304         LOG.debug("Added ARP DVR MAC flow for %s", mac)
  305 
  306     def _remove_dvr_mac(self, mac):
  307         for physical_network in self.bridge_mappings:
  308             self._remove_dvr_mac_for_phys_br(physical_network, mac)
  309         if self.enable_tunneling:
  310             self._remove_dvr_mac_for_tun_br(mac)
  311         LOG.debug("Removed DVR MAC flow for %s", mac)
  312         self.registered_dvr_macs.remove(mac)
  313 
  314     def setup_dvr_mac_flows_on_all_brs(self):
  315         dvr_macs = self.plugin_rpc.get_dvr_mac_address_list(self.context)
  316         LOG.debug("L2 Agent DVR: Received these MACs: %r", dvr_macs)
  317         for mac in dvr_macs:
  318             c_mac = netaddr.EUI(mac['mac_address'],
  319                                 dialect=netaddr.mac_unix_expanded)
  320             if c_mac == self.dvr_mac_address:
  321                 self._add_dvr_mac_for_arp(c_mac)
  322                 LOG.debug("Added the DVR MAC rule for ARP %s", c_mac)
  323                 continue
  324             self._add_dvr_mac(c_mac)
  325 
  326     def dvr_mac_address_update(self, dvr_macs):
  327         if not self.dvr_mac_address:
  328             LOG.debug("Self mac unknown, ignoring this "
  329                       "dvr_mac_address_update() ")
  330             return
  331 
  332         dvr_host_macs = set()
  333         for entry in dvr_macs:
  334             e_mac = netaddr.EUI(entry['mac_address'],
  335                                 dialect=netaddr.mac_unix_expanded)
  336             if e_mac == self.dvr_mac_address:
  337                 continue
  338             dvr_host_macs.add(e_mac)
  339 
  340         if dvr_host_macs == self.registered_dvr_macs:
  341             LOG.debug("DVR Mac address already up to date")
  342             return
  343 
  344         dvr_macs_added = dvr_host_macs - self.registered_dvr_macs
  345         dvr_macs_removed = self.registered_dvr_macs - dvr_host_macs
  346 
  347         for oldmac in dvr_macs_removed:
  348             self._remove_dvr_mac(oldmac)
  349 
  350         for newmac in dvr_macs_added:
  351             self._add_dvr_mac(newmac)
  352 
  353     def in_distributed_mode(self):
  354         return self.dvr_mac_address is not None
  355 
  356     def process_tunneled_network(self, network_type, lvid, segmentation_id):
  357         self.tun_br.provision_local_vlan(
  358             network_type=network_type,
  359             lvid=lvid,
  360             segmentation_id=segmentation_id,
  361             distributed=self.in_distributed_mode())
  362 
  363     def _bind_distributed_router_interface_port(self, port, lvm,
  364                                                 fixed_ips, device_owner):
  365         # since distributed router port must have only one fixed
  366         # IP, directly use fixed_ips[0]
  367         fixed_ip = fixed_ips[0]
  368         subnet_uuid = fixed_ip['subnet_id']
  369         if subnet_uuid in self.local_dvr_map:
  370             ldm = self.local_dvr_map[subnet_uuid]
  371         else:
  372             # set up LocalDVRSubnetMapping available for this subnet
  373             subnet_info = self.plugin_rpc.get_subnet_for_dvr(
  374                 self.context, subnet_uuid, fixed_ips=fixed_ips)
  375             if not subnet_info:
  376                 LOG.warning("DVR: Unable to retrieve subnet information "
  377                             "for subnet_id %s. The subnet or the gateway "
  378                             "may have already been deleted", subnet_uuid)
  379                 return
  380             LOG.debug("get_subnet_for_dvr for subnet %(uuid)s "
  381                       "returned with %(info)s",
  382                       {"uuid": subnet_uuid, "info": subnet_info})
  383             ldm = LocalDVRSubnetMapping(subnet_info)
  384             self.local_dvr_map[subnet_uuid] = ldm
  385 
  386         # DVR takes over
  387         ldm.set_dvr_owned(True)
  388 
  389         vlan_to_use = lvm.vlan
  390         if lvm.network_type == n_const.TYPE_VLAN:
  391             vlan_to_use = lvm.segmentation_id
  392 
  393         subnet_info = ldm.get_subnet_info()
  394         ip_version = subnet_info['ip_version']
  395         local_compute_ports = (
  396             self.plugin_rpc.get_ports_on_host_by_subnet(
  397                 self.context, self.host, subnet_uuid))
  398         LOG.debug("DVR: List of ports received from "
  399                   "get_ports_on_host_by_subnet %s",
  400                   local_compute_ports)
  401         vif_by_id = self.int_br.get_vifs_by_ids(
  402             [local_port['id'] for local_port in local_compute_ports])
  403         for local_port in local_compute_ports:
  404             vif = vif_by_id.get(local_port['id'])
  405             if not vif:
  406                 continue
  407             ldm.add_compute_ofport(vif.vif_id, vif.ofport)
  408             if vif.vif_id in self.local_ports:
  409                 # ensure if a compute port is already on
  410                 # a different dvr routed subnet
  411                 # if yes, queue this subnet to that port
  412                 comp_ovsport = self.local_ports[vif.vif_id]
  413                 comp_ovsport.add_subnet(subnet_uuid)
  414             else:
  415                 # the compute port is discovered first here that its on
  416                 # a dvr routed subnet queue this subnet to that port
  417                 comp_ovsport = OVSPort(vif.vif_id, vif.ofport,
  418                                        vif.vif_mac, local_port['device_owner'])
  419                 comp_ovsport.add_subnet(subnet_uuid)
  420                 self.local_ports[vif.vif_id] = comp_ovsport
  421             # create rule for just this vm port
  422             self.int_br.install_dvr_to_src_mac(
  423                 network_type=lvm.network_type,
  424                 vlan_tag=vlan_to_use,
  425                 gateway_mac=subnet_info['gateway_mac'],
  426                 dst_mac=comp_ovsport.get_mac(),
  427                 dst_port=comp_ovsport.get_ofport())
  428         # Add the following flow rule only when ARP RESPONDER is
  429         # enabled
  430         if self.arp_responder_enabled:
  431             self.int_br.install_dvr_dst_mac_for_arp(
  432                 lvm.network_type,
  433                 vlan_tag=lvm.vlan,
  434                 gateway_mac=port.vif_mac,
  435                 dvr_mac=self.dvr_mac_address,
  436                 rtr_port=port.ofport)
  437 
  438         if lvm.network_type == n_const.TYPE_VLAN:
  439             # TODO(vivek) remove the IPv6 related flows once SNAT is not
  440             # used for IPv6 DVR.
  441             br = self.phys_brs[lvm.physical_network]
  442         if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
  443             br = self.tun_br
  444         # TODO(vivek) remove the IPv6 related flows once SNAT is not
  445         # used for IPv6 DVR.
  446         if ip_version == 4:
  447             br.install_dvr_process_ipv4(
  448                 vlan_tag=lvm.vlan, gateway_ip=fixed_ip['ip_address'])
  449         else:
  450             br.install_dvr_process_ipv6(
  451                 vlan_tag=lvm.vlan, gateway_mac=port.vif_mac)
  452         br.install_dvr_process(
  453             vlan_tag=lvm.vlan, vif_mac=port.vif_mac,
  454             dvr_mac_address=self.dvr_mac_address)
  455 
  456         # the dvr router interface is itself a port, so capture it
  457         # queue this subnet to that port. A subnet appears only once as
  458         # a router interface on any given router
  459         ovsport = OVSPort(port.vif_id, port.ofport,
  460                           port.vif_mac, device_owner)
  461         ovsport.add_subnet(subnet_uuid)
  462         self.local_ports[port.vif_id] = ovsport
  463 
  464     def _bind_port_on_dvr_subnet(self, port, lvm, fixed_ips,
  465                                  device_owner):
  466         # Handle new compute port added use-case
  467         subnet_uuid = None
  468         for ips in fixed_ips:
  469             if ips['subnet_id'] not in self.local_dvr_map:
  470                 continue
  471             subnet_uuid = ips['subnet_id']
  472             ldm = self.local_dvr_map[subnet_uuid]
  473             if not ldm.is_dvr_owned():
  474                 # well this is CSNAT stuff, let dvr come in
  475                 # and do plumbing for this vm later
  476                 continue
  477 
  478             # This confirms that this compute port belongs
  479             # to a dvr hosted subnet.
  480             # Accommodate this VM Port into the existing rule in
  481             # the integration bridge
  482             LOG.debug("DVR: Plumbing compute port %s", port.vif_id)
  483             subnet_info = ldm.get_subnet_info()
  484             ldm.add_compute_ofport(port.vif_id, port.ofport)
  485             if port.vif_id in self.local_ports:
  486                 # ensure if a compute port is already on a different
  487                 # dvr routed subnet
  488                 # if yes, queue this subnet to that port
  489                 ovsport = self.local_ports[port.vif_id]
  490                 ovsport.add_subnet(subnet_uuid)
  491             else:
  492                 # the compute port is discovered first here that its
  493                 # on a dvr routed subnet, queue this subnet to that port
  494                 ovsport = OVSPort(port.vif_id, port.ofport,
  495                                   port.vif_mac, device_owner)
  496                 ovsport.add_subnet(subnet_uuid)
  497                 self.local_ports[port.vif_id] = ovsport
  498             vlan_to_use = lvm.vlan
  499             if lvm.network_type == n_const.TYPE_VLAN:
  500                 vlan_to_use = lvm.segmentation_id
  501             # create a rule for this vm port
  502             self.int_br.install_dvr_to_src_mac(
  503                 network_type=lvm.network_type,
  504                 vlan_tag=vlan_to_use,
  505                 gateway_mac=subnet_info['gateway_mac'],
  506                 dst_mac=ovsport.get_mac(),
  507                 dst_port=ovsport.get_ofport())
  508 
  509     def _bind_centralized_snat_port_on_dvr_subnet(self, port, lvm,
  510                                                   fixed_ips, device_owner):
  511         # We only pass the subnet uuid so the server code will correctly
  512         # use the gateway_ip value from the subnet when looking up the
  513         # centralized-SNAT (CSNAT) port, get it early from the first fixed_ip.
  514         subnet_uuid = fixed_ips[0]['subnet_id']
  515         if port.vif_id in self.local_ports:
  516             # throw an error if CSNAT port is already on a different
  517             # dvr routed subnet
  518             ovsport = self.local_ports[port.vif_id]
  519             subs = list(ovsport.get_subnets())
  520             if subs[0] == subnet_uuid:
  521                 return
  522             LOG.error("Centralized-SNAT port %(port)s on subnet "
  523                       "%(port_subnet)s already seen on a different "
  524                       "subnet %(orig_subnet)s", {
  525                           "port": port.vif_id,
  526                           "port_subnet": subnet_uuid,
  527                           "orig_subnet": subs[0],
  528                       })
  529             return
  530         ldm = None
  531         subnet_info = None
  532         if subnet_uuid not in self.local_dvr_map:
  533             # no csnat ports seen on this subnet - create csnat state
  534             # for this subnet
  535             subnet_info = self.plugin_rpc.get_subnet_for_dvr(
  536                 self.context, subnet_uuid, fixed_ips=None)
  537             if not subnet_info:
  538                 LOG.warning("DVR: Unable to retrieve subnet information "
  539                             "for subnet_id %s. The subnet or the gateway "
  540                             "may have already been deleted", subnet_uuid)
  541                 return
  542             LOG.debug("get_subnet_for_dvr for subnet %(uuid)s "
  543                       "returned with %(info)s",
  544                       {"uuid": subnet_uuid, "info": subnet_info})
  545             ldm = LocalDVRSubnetMapping(subnet_info, port.ofport)
  546             self.local_dvr_map[subnet_uuid] = ldm
  547         else:
  548             ldm = self.local_dvr_map[subnet_uuid]
  549             subnet_info = ldm.get_subnet_info()
  550             # Store csnat OF Port in the existing DVRSubnetMap
  551             ldm.set_csnat_ofport(port.ofport)
  552 
  553         # create ovsPort footprint for csnat port
  554         ovsport = OVSPort(port.vif_id, port.ofport,
  555                           port.vif_mac, device_owner)
  556         ovsport.add_subnet(subnet_uuid)
  557         self.local_ports[port.vif_id] = ovsport
  558         vlan_to_use = lvm.vlan
  559         if lvm.network_type == n_const.TYPE_VLAN:
  560             vlan_to_use = lvm.segmentation_id
  561         self.int_br.install_dvr_to_src_mac(
  562             network_type=lvm.network_type,
  563             vlan_tag=vlan_to_use,
  564             gateway_mac=subnet_info['gateway_mac'],
  565             dst_mac=ovsport.get_mac(),
  566             dst_port=ovsport.get_ofport())
  567 
  568     def bind_port_to_dvr(self, port, local_vlan_map,
  569                          fixed_ips, device_owner):
  570         if not self.in_distributed_mode():
  571             return
  572 
  573         if local_vlan_map.network_type not in (constants.TUNNEL_NETWORK_TYPES +
  574                                                [n_const.TYPE_VLAN]):
  575             LOG.debug("DVR: Port %s is with network_type %s not supported"
  576                       " for dvr plumbing", port.vif_id,
  577                       local_vlan_map.network_type)
  578             return
  579 
  580         if (port.vif_id in self.local_ports and
  581                 self.local_ports[port.vif_id].ofport != port.ofport):
  582             LOG.info("DVR: Port %(vif)s changed port number to "
  583                      "%(ofport)s, rebinding.",
  584                      {'vif': port.vif_id, 'ofport': port.ofport})
  585             self.unbind_port_from_dvr(port, local_vlan_map)
  586         if device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE:
  587             self._bind_distributed_router_interface_port(port,
  588                                                          local_vlan_map,
  589                                                          fixed_ips,
  590                                                          device_owner)
  591 
  592         if device_owner and n_utils.is_dvr_serviced(device_owner):
  593             self._bind_port_on_dvr_subnet(port, local_vlan_map,
  594                                           fixed_ips,
  595                                           device_owner)
  596 
  597         if device_owner == n_const.DEVICE_OWNER_ROUTER_SNAT:
  598             self._bind_centralized_snat_port_on_dvr_subnet(port,
  599                                                            local_vlan_map,
  600                                                            fixed_ips,
  601                                                            device_owner)
  602 
  603     def _unbind_distributed_router_interface_port(self, port, lvm):
  604         ovsport = self.local_ports[port.vif_id]
  605         # removal of distributed router interface
  606         subnet_ids = ovsport.get_subnets()
  607         subnet_set = set(subnet_ids)
  608         network_type = lvm.network_type
  609         physical_network = lvm.physical_network
  610         vlan_to_use = lvm.vlan
  611         if network_type == n_const.TYPE_VLAN:
  612             vlan_to_use = lvm.segmentation_id
  613         # ensure we process for all the subnets laid on this removed port
  614         for sub_uuid in subnet_set:
  615             if sub_uuid not in self.local_dvr_map:
  616                 continue
  617             ldm = self.local_dvr_map[sub_uuid]
  618             subnet_info = ldm.get_subnet_info()
  619             ip_version = subnet_info['ip_version']
  620             # DVR is no more owner
  621             ldm.set_dvr_owned(False)
  622             # remove all vm rules for this dvr subnet
  623             # clear of compute_ports altogether
  624             compute_ports = ldm.get_compute_ofports()
  625             for vif_id in compute_ports:
  626                 comp_port = self.local_ports[vif_id]
  627                 self.int_br.delete_dvr_to_src_mac(
  628                     network_type=network_type,
  629                     vlan_tag=vlan_to_use, dst_mac=comp_port.get_mac())
  630             ldm.remove_all_compute_ofports()
  631             # If ARP Responder enabled, remove the rule that redirects
  632             # the dvr_mac_address destination to the router port, since
  633             # the router port is removed or unbound.
  634             if self.arp_responder_enabled:
  635                 self.int_br.delete_dvr_dst_mac_for_arp(
  636                     network_type=network_type,
  637                     vlan_tag=vlan_to_use,
  638                     gateway_mac=port.vif_mac,
  639                     dvr_mac=self.dvr_mac_address,
  640                     rtr_port=port.ofport)
  641             if ldm.get_csnat_ofport() == constants.OFPORT_INVALID:
  642                 # if there is no csnat port for this subnet, remove
  643                 # this subnet from local_dvr_map, as no dvr (or) csnat
  644                 # ports available on this agent anymore
  645                 self.local_dvr_map.pop(sub_uuid, None)
  646             if network_type == n_const.TYPE_VLAN:
  647                 br = self.phys_brs[physical_network]
  648             if network_type in constants.TUNNEL_NETWORK_TYPES:
  649                 br = self.tun_br
  650             if ip_version == 4:
  651                 if subnet_info['gateway_ip']:
  652                     br.delete_dvr_process_ipv4(
  653                         vlan_tag=lvm.vlan,
  654                         gateway_ip=subnet_info['gateway_ip'])
  655             else:
  656                 br.delete_dvr_process_ipv6(
  657                     vlan_tag=lvm.vlan, gateway_mac=subnet_info['gateway_mac'])
  658             ovsport.remove_subnet(sub_uuid)
  659 
  660         if lvm.network_type == n_const.TYPE_VLAN:
  661             br = self.phys_brs[physical_network]
  662         if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
  663             br = self.tun_br
  664         br.delete_dvr_process(vlan_tag=lvm.vlan, vif_mac=port.vif_mac)
  665 
  666         # release port state
  667         self.local_ports.pop(port.vif_id, None)
  668 
  669     def _unbind_port_on_dvr_subnet(self, port, lvm):
  670         ovsport = self.local_ports[port.vif_id]
  671         # This confirms that this compute port being removed belonged
  672         # to a dvr hosted subnet.
  673         LOG.debug("DVR: Removing plumbing for compute port %s", port)
  674         subnet_ids = ovsport.get_subnets()
  675         # ensure we process for all the subnets laid on this port
  676         for sub_uuid in subnet_ids:
  677             if sub_uuid not in self.local_dvr_map:
  678                 continue
  679             ldm = self.local_dvr_map[sub_uuid]
  680             ldm.remove_compute_ofport(port.vif_id)
  681             vlan_to_use = lvm.vlan
  682             if lvm.network_type == n_const.TYPE_VLAN:
  683                 vlan_to_use = lvm.segmentation_id
  684             # first remove this vm port rule
  685             self.int_br.delete_dvr_to_src_mac(
  686                 network_type=lvm.network_type,
  687                 vlan_tag=vlan_to_use, dst_mac=ovsport.get_mac())
  688         # release port state
  689         self.local_ports.pop(port.vif_id, None)
  690 
  691     def _unbind_centralized_snat_port_on_dvr_subnet(self, port, lvm):
  692         ovsport = self.local_ports[port.vif_id]
  693         # This confirms that this compute port being removed belonged
  694         # to a dvr hosted subnet.
  695         LOG.debug("DVR: Removing plumbing for csnat port %s", port)
  696         sub_uuid = list(ovsport.get_subnets())[0]
  697         # ensure we process for all the subnets laid on this port
  698         if sub_uuid not in self.local_dvr_map:
  699             return
  700         ldm = self.local_dvr_map[sub_uuid]
  701         ldm.set_csnat_ofport(constants.OFPORT_INVALID)
  702         vlan_to_use = lvm.vlan
  703         if lvm.network_type == n_const.TYPE_VLAN:
  704             vlan_to_use = lvm.segmentation_id
  705         # then remove csnat port rule
  706         self.int_br.delete_dvr_to_src_mac(
  707             network_type=lvm.network_type,
  708             vlan_tag=vlan_to_use, dst_mac=ovsport.get_mac())
  709         if not ldm.is_dvr_owned():
  710             # if not owned by DVR (only used for csnat), remove this
  711             # subnet state altogether
  712             self.local_dvr_map.pop(sub_uuid, None)
  713         # release port state
  714         self.local_ports.pop(port.vif_id, None)
  715 
  716     def unbind_port_from_dvr(self, vif_port, local_vlan_map):
  717         if not self.in_distributed_mode():
  718             return
  719         # Handle port removed use-case
  720         if vif_port and vif_port.vif_id not in self.local_ports:
  721             LOG.debug("DVR: Non distributed port, ignoring %s", vif_port)
  722             return
  723 
  724         ovsport = self.local_ports[vif_port.vif_id]
  725         device_owner = ovsport.get_device_owner()
  726 
  727         if device_owner == n_const.DEVICE_OWNER_DVR_INTERFACE:
  728             self._unbind_distributed_router_interface_port(vif_port,
  729                                                            local_vlan_map)
  730 
  731         if device_owner and n_utils.is_dvr_serviced(device_owner):
  732             self._unbind_port_on_dvr_subnet(vif_port,
  733                                             local_vlan_map)
  734 
  735         if device_owner == n_const.DEVICE_OWNER_ROUTER_SNAT:
  736             self._unbind_centralized_snat_port_on_dvr_subnet(vif_port,
  737                                                              local_vlan_map)