text: from oslo.config import cfg
  
  from ryu.ofproto import ether
  from ryu.ofproto import inet
  from ryu.lib import dpid as dpid_lib
  from ryu.ofproto.ofproto_v1_0_parser import NXActionResubmitTable
  
  from daoliagent.lib import utils
  from daoliagent.lib import BMAX, BROADCAST
  from daoliagent.lib import PRIORITY
  from daoliagent.services.base import PacketBase
  from daoliagent.openstack.common import log as logging
  
  CONF = cfg.CONF
  LOG = logging.getLogger(__name__)
  
  class PacketIPv4(PacketBase):
      priority = 1
  
      def _input_output_kwargs(self, pkt_ipv4, pkt_tp, ofp_set, key=0):
          if pkt_ipv4.proto == inet.IPPROTO_TCP:
              output_local_kwargs = {'tcp_src': pkt_tp.src_port,
                                     'tcp_dst': pkt_tp.dst_port}
              output_local_src = ofp_set(tcp_src=key)
              input_local_kwargs = {'tcp_src': pkt_tp.dst_port,
                                    'tcp_dst': key}
              input_local_dst = ofp_set(tcp_dst=pkt_tp.src_port)
              input_remote_kwargs = {'tcp_src': key,
                                     'tcp_dst': pkt_tp.dst_port}
          elif pkt_ipv4.proto == inet.IPPROTO_UDP:
              output_local_kwargs = {'udp_src': pkt_tp.src_port,
                                     'udp_dst': pkt_tp.dst_port}
              output_local_src = ofp_set(udp_src=key)
              input_local_kwargs = {'udp_src': pkt_tp.dst_port,
                                    'udp_dst': key}
              input_local_dst = ofp_set(udp_dst=pkt_tp.src_port)
              input_remote_kwargs = {'udp_src': key,
                                     'udp_dst': pkt_tp.dst_port}
          else:
              output_local_kwargs = {'icmpv4_id': pkt_tp.id}
              output_local_src = ofp_set(icmpv4_id=key)
              input_local_kwargs = {'icmpv4_id': key}
              input_local_dst = ofp_set(icmpv4_id=pkt_tp.id)
              input_remote_kwargs = {'icmpv4_id': key}
  
          return (output_local_kwargs, input_local_kwargs, output_local_src,
                  input_local_dst, input_remote_kwargs)
  
      def _rarefaction_ip(self, msg, dp, in_port, key, pkt_ether, pkt_ipv4,
                          pkt_tp, src, src_gateway, dst, dst_gateway):
          ofp, ofp_parser, ofp_set, ofp_out = self.ofp_get(dp)
          liport = self.port_get(dp, devname=src_gateway['int_dev']).port_no
  
          rdp = self.ryuapp.dps[dpid_lib.str_to_dpid(dst_gateway['datapath_id'])]
          rofp, rofp_parser, rofp_set, rofp_out = self.ofp_get(rdp)
          riport = self.port_get(rdp, devname=dst_gateway['int_dev']).port_no
  
          (output_local_kwargs, input_local_kwargs, output_local_src,
           input_local_dst, input_remote_kwargs) = self._input_output_kwargs(
                  pkt_ipv4, pkt_tp, ofp_set, key)
  
          if pkt_ether.dst == dst['mac_address']:
              dst_srcmac = src['mac_address']
          else:
              dst_srcmac = dst_gateway['vint_mac']
  
          if src_gateway['idc_id'] == dst_gateway['idc_id']:
              output_local_actions = [ofp_set(eth_src=src_gateway['int_mac']),
                                      ofp_set(eth_dst=dst_gateway['int_mac']),
                                      ofp_set(ipv4_src=src_gateway['int_ip']),
                                      ofp_set(ipv4_dst=dst_gateway['int_ip']),
                                      output_local_src, ofp_out(liport)]
  
              input_local_match = ofp_parser.OFPMatch(
                      in_port=liport,
                      eth_type=ether.ETH_TYPE_IP,
                      eth_dst=src_gateway['int_mac'],
                      ip_proto=pkt_ipv4.proto,
                      ipv4_src=dst_gateway['int_ip'],
                      ipv4_dst=src_gateway['int_ip'],
                      **input_local_kwargs)
  
              input_remote_match = rofp_parser.OFPMatch(
                      in_port=riport,
                      eth_type=ether.ETH_TYPE_IP,
                      eth_dst=dst_gateway['int_mac'],
                      ip_proto=pkt_ipv4.proto,
                      ipv4_src=src_gateway['int_ip'],
                      ipv4_dst=dst_gateway['int_ip'],
                      **input_remote_kwargs)
  
              output_remote_actions = [rofp_set(eth_src=dst_gateway['int_mac']),
                                       rofp_set(eth_dst=src_gateway['int_mac']),
                                       rofp_set(ipv4_src=dst_gateway['int_ip']),
                                       rofp_set(ipv4_dst=src_gateway['int_ip']),
                                       rofp_out(riport)]
  
          else:
              src_gateways = self.db.gateway_get_by_idc(src_gateway['idc_id'])
              dst_gateways = self.db.gateway_get_by_idc(dst_gateway['idc_id'])
  
              if not src_gateways or not dst_gateways:
                  return
  
              src_dps = [g.datapath_id for g in src_gateways]
              dst_dps = [g.datapath_id for g in dst_gateways]
  
              lgdp_id = (src_dps[pkt_ipv4.identification % len(src_dps)]
                         if src_gateway['datapath_id'] not in src_dps else None)
              rgdp_id = (dst_dps[pkt_ipv4.identification % len(dst_dps)]
                         if dst_gateway['datapath_id'] not in dst_dps else None)
  
              input_remote_match, output_remote_actions = self._remote_gateway(
                      rdp, pkt_ipv4, src_gateway, dst_gateway, input_local_kwargs,
                      input_remote_kwargs, riport=riport, lgdp_id=lgdp_id, rgdp_id=rgdp_id)
              input_local_match, output_local_actions = self._local_gateway(
                      dp, pkt_ether, pkt_ipv4, src_gateway, dst_gateway,
                      output_local_src, input_local_dst, input_local_kwargs,
                      input_remote_kwargs, liport=liport, lgdp_id=lgdp_id, rgdp_id=rgdp_id)
  
          output_remote_match, input_remote_actions = self._remote_host(
                  rdp, pkt_ipv4, dst, dst_srcmac, input_local_kwargs)
          output_local_match, input_local_actions = self._local_host(dp,
                  in_port, pkt_ether, pkt_ipv4, input_local_dst, output_local_kwargs)
  
          self.add_flow(rdp, input_remote_match, input_remote_actions, priority=PRIORITY['internet'])
          self.add_flow(rdp, output_remote_match, output_remote_actions, priority=PRIORITY['internet'])
          self.add_flow(dp, input_local_match, input_local_actions, priority=PRIORITY['internet'])
          self.add_flow(dp, output_local_match, output_local_actions, priority=PRIORITY['internet'])
          self.packet_out(msg, dp, output_local_actions)
  
      def _remote_gateway(self, rdp, pkt_ipv4, src_gateway, dst_gateway, input_local_kwargs,
                          input_remote_kwargs, riport=None, lgdp_id=None, rgdp_id=None):
          rofp, rofp_parser, rofp_set, rofp_out = self.ofp_get(rdp)
  
          if lgdp_id is not None:
              src_ipv4 = self.manager.gateway[lgdp_id]['vext_ip']
          else:
              src_ipv4 = src_gateway['vext_ip']
  
          if rgdp_id is not None:
              if riport is None:
                  riport = self.port_get(rdp, devname=dst_gateway['int_dev']).port_no
  
              remote_gateway = self.manager.gateway[rgdp_id]
              rgdp = self.ryuapp.dps[dpid_lib.str_to_dpid(rgdp_id)]
              rgofp, rgofp_parser, rgofp_set, rgofp_out = self.ofp_get(rgdp)
              rgiport = self.port_get(rgdp, devname=remote_gateway['int_dev']).port_no
              rgeport = self.port_get(rgdp, devname=remote_gateway['ext_dev']).port_no
  
              input_remote_gateway_match = rgofp_parser.OFPMatch(
                      in_port=rgeport,
                      eth_type=ether.ETH_TYPE_IP,
                      eth_dst=remote_gateway['ext_mac'],
                      ip_proto=pkt_ipv4.proto,
                      ipv4_src=src_ipv4,
                      ipv4_dst=remote_gateway['ext_ip'],
                      **input_remote_kwargs)
  
              input_remote_gateway_actions = [rgofp_set(eth_src=remote_gateway['int_mac']),
                                              rgofp_set(eth_dst=dst_gateway['int_mac']),
                                              rgofp_set(ipv4_src=remote_gateway['int_ip']),
                                              rgofp_set(ipv4_dst=dst_gateway['int_ip']),
                                              rgofp_out(rgiport)]
  
              output_remote_gateway_match = rgofp_parser.OFPMatch(
                      in_port=rgiport,
                      eth_type=ether.ETH_TYPE_IP,
                      eth_dst=remote_gateway['int_mac'],
                      ip_proto=pkt_ipv4.proto,
                      ipv4_src=dst_gateway['int_ip'],
                      ipv4_dst=remote_gateway['int_ip'],
                      **input_local_kwargs)
  
              output_remote_gateway_actions = [rgofp_set(eth_src=remote_gateway['ext_mac']),
                                               rgofp_set(eth_dst=remote_gateway['idc_mac']),
                                               rgofp_set(ipv4_src=remote_gateway['ext_ip']),
                                               rgofp_set(ipv4_dst=src_ipv4),
                                               rgofp_out(rgeport)]
  
              input_remote_match = rofp_parser.OFPMatch(
                      in_port=riport,
                      eth_type=ether.ETH_TYPE_IP,
                      eth_dst=dst_gateway['int_mac'],
                      ip_proto=pkt_ipv4.proto,
                      ipv4_src=remote_gateway['int_ip'],
                      ipv4_dst=dst_gateway['int_ip'],
                      **input_remote_kwargs)
  
              output_remote_actions = [rofp_set(eth_src=dst_gateway['int_mac']),
                                       rofp_set(eth_dst=remote_gateway['int_mac']),
                                       rofp_set(ipv4_src=dst_gateway['int_ip']),
                                       rofp_set(ipv4_dst=remote_gateway['int_ip']),
                                       rofp_out(riport)]
  
              self.add_flow(rgdp, input_remote_gateway_match,
                            input_remote_gateway_actions,
                            priority=PRIORITY['internet'])
              self.add_flow(rgdp, output_remote_gateway_match,
                            output_remote_gateway_actions,
                            priority=PRIORITY['internet'])
          else:
              report = self.port_get(rdp, devname=dst_gateway['ext_dev']).port_no
  
              input_remote_match = rofp_parser.OFPMatch(
                      in_port=report,
                      eth_type=ether.ETH_TYPE_IP,
                      eth_dst=dst_gateway['ext_mac'],
                      ip_proto=pkt_ipv4.proto,
                      ipv4_src=src_ipv4,
                      ipv4_dst=dst_gateway['ext_ip'],
                      **input_remote_kwargs)
  
              output_remote_actions = [rofp_set(eth_src=dst_gateway['ext_mac']),
                                       rofp_set(eth_dst=dst_gateway['idc_mac']),
                                       rofp_set(ipv4_src=dst_gateway['ext_ip']),
                                       rofp_set(ipv4_dst=src_ipv4),
                                       rofp_out(report)]
  
          return (input_remote_match, output_remote_actions)
  
      def _remote_host(self, rdp, pkt_ipv4, dst, dst_srcmac, input_local_kwargs):
          rofp, rofp_parser, rofp_set, rofp_out = self.ofp_get(rdp)
          dst_port = self.port_get(rdp, dst['id']).port_no
  
          input_remote_actions = [rofp_set(eth_src=dst_srcmac),
                                  rofp_set(eth_dst=dst['mac_address']),
                                  rofp_set(ipv4_src=pkt_ipv4.src),
                                  rofp_set(ipv4_dst=pkt_ipv4.dst),
                                  rofp_out(dst_port)]
  
          output_remote_match = rofp_parser.OFPMatch(
                  in_port=dst_port,
                  eth_type=ether.ETH_TYPE_IP,
                  eth_src=dst['mac_address'],
                  ip_proto=pkt_ipv4.proto,
                  ipv4_src=pkt_ipv4.dst,
                  ipv4_dst=pkt_ipv4.src,
                  **input_local_kwargs)
  
          return (output_remote_match, input_remote_actions)
  
      def _local_host(self, dp, in_port, pkt_ether, pkt_ipv4, input_local_dst, output_local_kwargs):
          ofp, ofp_parser, ofp_set, ofp_out = self.ofp_get(dp)
  
          output_local_match = ofp_parser.OFPMatch(
                  in_port=in_port,
                  eth_type=ether.ETH_TYPE_IP,
                  eth_src=pkt_ether.src,
                  ip_proto=pkt_ipv4.proto,
                  ipv4_src=pkt_ipv4.src,
                  ipv4_dst=pkt_ipv4.dst,
                  **output_local_kwargs)
  
          input_local_actions = [ofp_set(eth_src=pkt_ether.dst),
                                 ofp_set(eth_dst=pkt_ether.src),
                                 ofp_set(ipv4_src=pkt_ipv4.dst),
                                 ofp_set(ipv4_dst=pkt_ipv4.src),
                                 input_local_dst, ofp_out(in_port)]
  
          return (output_local_match, input_local_actions)
  
      def _local_gateway(self, dp, pkt_ether, pkt_ipv4, src_gateway, dst_gateway,
                         output_local_src, input_local_dst, input_local_kwargs,
                         input_remote_kwargs, liport=None, lgdp_id=None, rgdp_id=None,
                         public=False):
          ofp, ofp_parser, ofp_set, ofp_out = self.ofp_get(dp)
  
          if not public:
              if rgdp_id is None:
                  ipv4_dst = dst_gateway['vext_ip']
              else:
                  remote_gateway = self.manager.gateway[rgdp_id]
                  ipv4_dst = remote_gateway['vext_ip']
          else:
              ipv4_dst = pkt_ipv4.dst
  
          if lgdp_id is not None:
              if liport is None:
                  liport = self.port_get(dp, devname=src_gateway['int_dev']).port_no
              local_gateway = self.manager.gateway[lgdp_id]
              lgdp = self.ryuapp.dps[dpid_lib.str_to_dpid(lgdp_id)]
              lgofp, lgofp_parser, lgofp_set, lgofp_out = self.ofp_get(lgdp)
              lgiport = self.port_get(lgdp, devname=local_gateway['int_dev']).port_no
              lgeport = self.port_get(lgdp, devname=local_gateway['ext_dev']).port_no
  
              output_local_actions = [ofp_set(eth_src=src_gateway['int_mac']),
                                      ofp_set(eth_dst=local_gateway['int_mac']),
                                      ofp_set(ipv4_src=src_gateway['int_ip']),
                                      ofp_set(ipv4_dst=local_gateway['int_ip']),
                                      output_local_src, ofp_out(liport)]
  
              input_local_match = ofp_parser.OFPMatch(
                      in_port=liport,
                      eth_type=ether.ETH_TYPE_IP,
                      eth_dst=src_gateway['int_mac'],
                      ip_proto=pkt_ipv4.proto,
                      ipv4_src=local_gateway['int_ip'],
                      ipv4_dst=src_gateway['int_ip'],
                      **input_local_kwargs)
  
              input_local_gateway_match = lgofp_parser.OFPMatch(
                      in_port=lgiport,
                      eth_type=ether.ETH_TYPE_IP,
                      eth_dst=local_gateway['int_mac'],
                      ip_proto=pkt_ipv4.proto,
                      ipv4_src=src_gateway['int_ip'],
                      ipv4_dst=local_gateway['int_ip'],
                      **input_remote_kwargs)
  
              input_local_gateway_actions = [lgofp_set(eth_src=local_gateway['ext_mac']),
                                             lgofp_set(eth_dst=local_gateway['idc_mac']),
                                             lgofp_set(ipv4_src=local_gateway['ext_ip']),
                                             lgofp_set(ipv4_dst=ipv4_dst), lgofp_out(lgeport)]
  
              output_local_gateway_match = lgofp_parser.OFPMatch(
                      in_port=lgeport,
                      eth_type=ether.ETH_TYPE_IP,
                      eth_dst=local_gateway['ext_mac'],
                      ip_proto=pkt_ipv4.proto,
                      ipv4_src=ipv4_dst,
                      ipv4_dst=local_gateway['ext_ip'],
                      **input_local_kwargs)
  
              output_local_gateway_actions = [lgofp_set(eth_src=local_gateway['int_mac']),
                                              lgofp_set(eth_dst=src_gateway['int_mac']),
                                              lgofp_set(ipv4_src=local_gateway['int_ip']),
                                              lgofp_set(ipv4_dst=src_gateway['int_ip']),
                                              lgofp_out(lgiport)]
  
              self.add_flow(lgdp, input_local_gateway_match,
                            input_local_gateway_actions,
                            priority=PRIORITY['internet'])
              self.add_flow(lgdp, output_local_gateway_match,
                            output_local_gateway_actions,
                            priority=PRIORITY['internet'])
          else:
              leport = self.port_get(dp, devname=src_gateway['ext_dev']).port_no
  
              output_local_actions = [ofp_set(eth_src=src_gateway['ext_mac']),
                                      ofp_set(eth_dst=src_gateway['idc_mac']),
                                      ofp_set(ipv4_src=src_gateway['ext_ip']),
                                      ofp_set(ipv4_dst=ipv4_dst),
                                      output_local_src, ofp_out(leport)]
  
              input_local_match = ofp_parser.OFPMatch(
                      in_port=leport,
                      eth_type=ether.ETH_TYPE_IP,
                      eth_dst=src_gateway['ext_mac'],
                      ip_proto=pkt_ipv4.proto,
                      ipv4_src=ipv4_dst,
                      ipv4_dst=src_gateway['ext_ip'],
                      **input_local_kwargs)
  
          return (input_local_match, output_local_actions)
  
      def _redirect(self, msg, dp, in_port, pkt_ether, pkt_ipv4, output, **kwargs):
          ofp, ofp_parser, ofp_set, ofp_out = self.ofp_get(dp)
          match = ofp_parser.OFPMatch(
                  in_port=in_port, eth_type=ether.ETH_TYPE_IP,
                  ip_proto=pkt_ipv4.proto,
                  eth_src=pkt_ether.src, eth_dst=pkt_ether.dst,
                  ipv4_src=pkt_ipv4.src, ipv4_dst=pkt_ipv4.dst,
                  **kwargs)
  
          actions = [ofp_parser.OFPActionOutput(output)]
  
          self.add_flow(dp, match, actions)
          self.packet_out(msg, dp, actions)
  
  
      def firewall(self, msg, dp, in_port, pkt_ether, pkt_ipv4, pkt_tp, gateway):
          ofp, ofp_parser, ofp_set, ofp_out = self.ofp_get(dp)
  
          output_local_kwargs = self._input_output_kwargs(pkt_ipv4, pkt_tp, ofp_set)[0]
  
          if gateway['int_dev'] != gateway['ext_dev']:
              int_port = self.port_get(dp, devname=gateway['int_dev'])
  
              if not int_port or (in_port == int_port.port_no and 
                                  pkt_ipv4.dst != gateway['int_ip'] and
                                  pkt_ipv4.dst != BROADCAST):
                  return True
  
              tap_port = self.port_get(dp, devname=gateway['vint_dev'])
  
              if not tap_port or (in_port == tap_port.port_no and
                                  pkt_ipv4.src != gateway['int_ip']):
                  return True
  
              if in_port == int_port.port_no or in_port == tap_port.port_no:
                  if in_port == int_port.port_no:
                      output = tap_port.port_no
                  else:
                      output = int_port.port_no
  
                  self._redirect(msg, dp, in_port, pkt_ether, pkt_ipv4,
                                 output, **output_local_kwargs)
                  return True
  
          port = self.port_get(dp, devname=gateway['ext_dev'])
          if not port:
              return True
  
          if in_port == port.port_no and pkt_ipv4.dst not in (gateway['ext_ip'], BROADCAST):
              return True
  
          if in_port == ofp.OFPP_LOCAL and pkt_ipv4.src != gateway['ext_ip']:
              return True
  
          if in_port == port.port_no or in_port == dp.ofproto.OFPP_LOCAL:
              # ICMP Packet redirect to physical host
              if pkt_ipv4.proto != inet.IPPROTO_ICMP:
                  server = self.db.firewall_get_by_packet(
                          gateway['hostname'], pkt_tp.dst_port)
                  if server:
                      if pkt_ipv4.proto == inet.IPPROTO_TCP:
                          output_key = ofp_set(tcp_src=pkt_tp.dst_port)
                          input_key = ofp_set(tcp_dst=server.service_port)
                          output_kwargs = {'tcp_src': server.service_port,
                                           'tcp_dst': pkt_tp.src_port}
                          input_kwargs = {'tcp_src': pkt_tp.src_port,
                                          'tcp_dst': server.service_port}
                      else:
                          output_key = ofp_set(udp_src=pkt_tp.dst_port)
                          input_key = ofp_set(udp_dst=server.service_port)
                          output_kwargs = {'udp_src': server.service_port,
                                           'udp_dst': pkt_tp.src_port}
                          input_kwargs = {'udp_src': pkt_tp.src,
                                          'udp_dst': server.service_port}
  
                      input_match, output_actions = self._local_host(
                              dp, in_port, pkt_ether, pkt_ipv4, output_key, output_local_kwargs)
  
                      if server.Instance['host'] == gateway['hostname']:
                          server_port = self.port_get(dp, server.Instance['id'])
  
                          # Virtual machine may be poweroff
                          if not server_port:
                              return True
  
                          input_actions = [ofp_set(eth_src=gateway['vint_mac']),
                                           ofp_set(eth_dst=server.Instance['mac_address']),
                                           ofp_set(ipv4_dst=server.Instance['address']),
                                           input_key, ofp_out(server_port.port_no)]
  
                          output_match = ofp_parser.OFPMatch(
                                  in_port=server_port.port_no,
                                  eth_type=ether.ETH_TYPE_IP,
                                  ip_proto=pkt_ipv4.proto,
                                  ipv4_src=server.Instance['address'],
                                  ipv4_dst=pkt_ipv4.src,
                                  **output_kwargs)
                      else:
                          ldp = self.ryuapp.dps[dpid_lib.str_to_dpid(server.Gateway['datapath_id'])]
                          lofp, lofp_parser, lofp_set, lofp_out = self.ofp_get(ldp)
                          liport = self.port_get(ldp, devname=server.Gateway['int_dev']).port_no
                          giport = self.port_get(dp, devname=gateway['int_dev']).port_no
  
                          server_port = self.port_get(ldp, server.Instance['id'])
  
                          # Virtual machine may be poweroff
                          if not server_port:
                              return True
  
                          input_actions = [ofp_set(eth_src=gateway['int_mac']),
                                           ofp_set(eth_dst=server.Gateway['int_mac']),
                                           ofp_set(ipv4_src=gateway['int_ip']),
                                           ofp_set(ipv4_dst=server.Gateway['int_ip']),
                                           input_key, ofp_out(giport)]
  
                          output_match = ofp_parser.OFPMatch(
                                  in_port=giport,
                                  eth_type=ether.ETH_TYPE_IP,
                                  eth_src=server.Gateway['int_mac'],
                                  eth_dst=gateway['int_mac'],
                                  ip_proto=pkt_ipv4.proto,
                                  ipv4_src=server.Gateway['int_ip'],
                                  ipv4_dst=gateway['int_ip'],
                                  **output_kwargs)
  
                          input_local_match = lofp_parser.OFPMatch(
                                  in_port=liport,
                                  eth_type=ether.ETH_TYPE_IP,
                                  eth_dst=server.Gateway['int_mac'],
                                  ip_proto=pkt_ipv4.proto,
                                  ipv4_src=gateway['int_ip'],
                                  ipv4_dst=server.Gateway['int_ip'],
                                  **input_kwargs)
  
                          input_local_actions = [lofp_set(eth_src=server.Gateway['vint_mac']),
                                                 lofp_set(eth_dst=server.Instance['mac_address']),
                                                 lofp_set(ipv4_src=pkt_ipv4.src),
                                                 lofp_set(ipv4_dst=server.Instance['address']),
                                                 lofp_out(server_port.port_no)]
  
                          output_local_match = lofp_parser.OFPMatch(
                                  in_port=server_port.port_no,
                                  eth_type=ether.ETH_TYPE_IP,
                                  eth_src=server.Instance['mac_address'],
                                  ip_proto=pkt_ipv4.proto,
                                  ipv4_src=server.Instance['address'],
                                  ipv4_dst=pkt_ipv4.src,
                                  **output_kwargs)
  
                          output_local_actions = [lofp_set(eth_src=server.Gateway['int_mac']),
                                                  lofp_set(eth_dst=gateway['int_mac']),
                                                  lofp_set(ipv4_src=server.Gateway['int_ip']),
                                                  lofp_set(ipv4_dst=gateway['int_ip']),
                                                  ofp_out(liport)]
                          self.add_flow(ldp, input_local_match, input_local_actions,
                                        priority=PRIORITY['firewall'])
                          self.add_flow(ldp, output_local_match, output_local_actions,
                                        priority=PRIORITY['firewall'])
  
                      self.add_flow(dp, output_match, output_actions, priority=PRIORITY['firewall'])
                      self.add_flow(dp, input_match, input_actions, priority=PRIORITY['firewall'])
                      self.packet_out(msg, dp, input_actions)
  
                      return True
  
              #self.redirect(msg, dp, in_port=in_port, eth_type=ether.ETH_TYPE_IP,
              #              ip_proto=pkt_ipv4.proto, eth_src=pkt_ether.src,
              #              ipv4_src=pkt_ipv4.src, ipv4_dst=pkt_ipv4.dst,
              #              **output_local_kwargs)
  
              if in_port == port.port_no:
                  output = ofp.OFPP_LOCAL
              else:
                  output = port.port_no
              
              self._redirect(msg, dp, in_port, pkt_ether, pkt_ipv4,
                             output, **output_local_kwargs)
              return True
          return False
  
      def run(self, msg, pkt_ether, pkt_ipv4, pkt_tp, src_gateway, **kwargs):
          dp = msg.datapath
          in_port = msg.match['in_port']
  
          if pkt_ipv4.proto == inet.IPPROTO_ICMP:
              key = utils.filter_port(pkt_tp.id)
          else:
              key = utils.filter_port(pkt_tp.src_port)
  
          if self.firewall(msg, dp, in_port, pkt_ether, pkt_ipv4, pkt_tp, src_gateway):
              return True
  
          servers = self.db.server_get_by_mac(pkt_ether.src, pkt_ipv4.dst)
          src, dst, has_more = (servers['src'], servers['dst'], servers['has_more'])
  
          if src is None or (dst is not None and not has_more):
              return False
  
          # Create nat flow if 'dst' instance is not null, else public flow
          if dst is not None:
              if src['host'] == dst['host']:
                  ofp, ofp_parser, ofp_set, ofp_out = self.ofp_get(dp)
  
                  change = (pkt_ether.dst if pkt_ether.dst != dst['mac_address'] else None)
  
                  def same_host_flow(smac, dmac, sip, dip, iport, oport):
                      match = ofp_parser.OFPMatch(
                              in_port=iport,
                              eth_type=ether.ETH_TYPE_IP,
                              eth_src=smac,
                              ipv4_src=sip,
                              ipv4_dst=dip)
                      actions = ([ofp_set(eth_src=change)] if change is not None else [])
                      actions += [ofp_set(eth_dst=dmac), ofp_out(oport)]
                      self.add_flow(dp, match, actions, priority=2)
  
                      return actions
  
                  dst_port = self.port_get(dp, dst['id']).port_no
                  same_host_flow(dst['mac_address'], src['mac_address'], pkt_ipv4.dst,
                                 pkt_ipv4.src, dst_port, in_port)
                  self.packet_out(msg, dp, same_host_flow(
                                  src['mac_address'], dst['mac_address'], pkt_ipv4.src,
                                  pkt_ipv4.dst, in_port, dst_port))
              else:
                  dst_gateway = self.db.gateway_get_by_name(dst['host'])
                  self._rarefaction_ip(msg, dp, in_port, key, pkt_ether, pkt_ipv4,
                                       pkt_tp, src, src_gateway, dst, dst_gateway)
          else:
              self._public_ip(msg, dp, in_port, key, pkt_ether, pkt_ipv4, pkt_tp, src, src_gateway)
  
      def _public_ip(self, msg, dp, in_port, key, pkt_ether, pkt_ipv4, pkt_tp, src, src_gateway):
          ofp, ofp_parser, ofp_set, ofp_out = self.ofp_get(dp)
  
          (output_local_kwargs, input_local_kwargs, output_local_src,
           input_local_dst, input_remote_kwargs) = self._input_output_kwargs(
                  pkt_ipv4, pkt_tp, ofp_set, key)
  
          if pkt_ipv4.proto == inet.IPPROTO_UDP and pkt_tp.dst_port == 67:
              gateway = src['address'].split('.')
              gateway[2] = str(BMAX)
              gateway[3] = str(BMAX - 1)
              match = ofp_parser.OFPMatch(in_port=in_port,
                                          eth_type=ether.ETH_TYPE_IP,
                                          ip_proto=pkt_ipv4.proto,
                                          ipv4_src='.'.join(gateway),
                                          **output_local_kwargs)
              actions = [ofp_set(eth_src=src_gateway['vint_mac']),
                         ofp_set(eth_dst=pkt_ether.src),
                         ofp_set(ipv4_src='.'.join(gateway)),
                         ofp_set(ipv4_dst=src['address']),
                         ofp_set(udp_src=pkt_tp.dst_port),
                         ofp_set(udp_dst=pkt_tp.src_port),
                         ofp_out(ofp.OFPP_IN_PORT)]
  
              self.add_flow(dp, match, actions, priority=PRIORITY['internet'])
              return self.packet_out(msg, dp, actions)
  
          gateways = self.db.gateway_get_by_idc(src_gateway.idc_id)
          gateway_dps = [g.datapath_id for g in gateways]
  
          if gateway_dps:
              lgdp_id = (gateway_dps[pkt_ipv4.identification % len(gateway_dps)]
                         if src_gateway['datapath_id'] not in gateway_dps else None)
  
              input_match, output_actions = self._local_gateway(
                      dp, pkt_ether, pkt_ipv4, src_gateway, None,
                      output_local_src, input_local_dst, input_local_kwargs,
                      input_remote_kwargs, lgdp_id=lgdp_id, public=True)
  
              output_match, input_actions = self._local_host(
                      dp, in_port, pkt_ether, pkt_ipv4, input_local_dst, output_local_kwargs)
  
              self.add_flow(dp, input_match, input_actions, priority=PRIORITY['internet'])
              self.add_flow(dp, output_match, output_actions, priority=PRIORITY['internet'])
              self.packet_out(msg, dp, output_actions)
          else:
              LOG.warn("Gateway not found - %s", src_gateway)
  