components/openstack/neutron/files/agent/evs_l3_agent.py
branchs11-update
changeset 3323 b4b74d363c31
parent 3200 16d08ab96b7f
child 3435 25a421888935
--- a/components/openstack/neutron/files/agent/evs_l3_agent.py	Tue Sep 23 10:06:56 2014 -0700
+++ b/components/openstack/neutron/files/agent/evs_l3_agent.py	Tue Sep 23 10:12:34 2014 -0700
@@ -260,81 +260,157 @@
                    gw_ip]
             utils.execute(cmd, check_exit_code=False)
 
+            # for each of the internal ports, add Policy Based
+            # Routing (PBR) rule
+            for port in ri.internal_ports:
+                internal_dlname = self.get_internal_device_name(port['id'])
+                rules = ['pass in on %s to %s:%s from any to any' %
+                         (internal_dlname, external_dlname, gw_ip)]
+                ipversion = netaddr.IPNetwork(port['subnet']['cidr']).version
+                ri.ipfilters_manager.add_ipf_rules(rules, ipversion)
+
     def external_gateway_removed(self, ri, ex_gw_port,
                                  external_dlname, internal_cidrs):
 
-        if net_lib.Datalink.datalink_exists(external_dlname):
-            self.driver.fini_l3(external_dlname)
-            self.driver.unplug(external_dlname)
         gw_ip = ex_gw_port['subnet']['gateway_ip']
         if gw_ip:
+            # remove PBR rules
+            for port in ri.internal_ports:
+                internal_dlname = self.get_internal_device_name(port['id'])
+                rules = ['pass in on %s to %s:%s from any to any' %
+                         (internal_dlname, external_dlname, gw_ip)]
+                ipversion = netaddr.IPNetwork(port['subnet']['cidr']).version
+                ri.ipfilters_manager.remove_ipf_rules(rules, ipversion)
+
             cmd = ['/usr/bin/pfexec', '/usr/sbin/route', 'delete', 'default',
                    gw_ip]
             utils.execute(cmd, check_exit_code=False)
 
-    def _get_ippool_name(self, mac_address):
-        # generate a unique-name for ippool(1m) from that last 3
-        # bytes of mac-address
-        mac_suffix = mac_address.split(':')[3:]
-        return int("".join(mac_suffix), 16)
+        if net_lib.Datalink.datalink_exists(external_dlname):
+            self.driver.fini_l3(external_dlname)
+            self.driver.unplug(external_dlname)
+
+    def _get_ippool_name(self, mac_address, suffix=None):
+        # Generate a unique-name for ippool(1m) from that last 3
+        # bytes of mac-address. It is called pool name, but it is
+        # actually a 32 bit integer
+        name = mac_address.split(':')[3:]
+        if suffix:
+            name.append(suffix)
+        return int("".join(name), 16)
 
     def internal_network_added(self, ri, port):
-
         internal_dlname = self.get_internal_device_name(port['id'])
-        if not net_lib.Datalink.datalink_exists(internal_dlname):
-            self.driver.plug(port['tenant_id'], port['network_id'], port['id'],
-                             internal_dlname)
+        # driver just returns if datalink and IP interface already exists
+        self.driver.plug(port['tenant_id'], port['network_id'], port['id'],
+                         internal_dlname)
         self.driver.init_l3(internal_dlname, [port['ip_cidr']])
 
-        # add ippool(1m) for the new internal port
-        new_ippool_name = self._get_ippool_name(port['mac_address'])
-        ri.ipfilters_manager.add_ippool(new_ippool_name, None)
+        # Since we support shared router model, we need to block the new
+        # internal port from reaching other tenant's ports
+        block_pname = self._get_ippool_name(port['mac_address'])
+        ri.ipfilters_manager.add_ippool(block_pname, None)
+        if self.conf.allow_forwarding_between_networks:
+            # If allow_forwarding_between_networks is set, then we need to
+            # allow forwarding of packets between same tenant's ports.
+            allow_pname = self._get_ippool_name(port['mac_address'], '0')
+            ri.ipfilters_manager.add_ippool(allow_pname, None)
 
         # walk through the other internal ports and retrieve their
         # cidrs and at the same time add the new internal port's
         # cidr to them
-        subnet_cidr = port['subnet']['cidr']
-        other_subnet_cidrs = []
-        for oip in ri.internal_ports:
-            if oip['mac_address'] != port['mac_address']:
-                if (self.conf.allow_forwarding_between_networks and
-                        oip['tenant_id'] == port['tenant_id']):
-                    continue
-                other_subnet_cidrs.append(oip['subnet']['cidr'])
-                ippool_name = self._get_ippool_name(oip['mac_address'])
-                ri.ipfilters_manager.add_ippool(ippool_name, [subnet_cidr])
-        # update the new port's pool with other port's cidrs
-        ri.ipfilters_manager.add_ippool(new_ippool_name, other_subnet_cidrs)
+        port_subnet = port['subnet']['cidr']
+        block_subnets = []
+        allow_subnets = []
+        for internal_port in ri.internal_ports:
+            if internal_port['mac_address'] == port['mac_address']:
+                continue
+            if (self.conf.allow_forwarding_between_networks and
+                    internal_port['tenant_id'] == port['tenant_id']):
+                allow_subnets.append(internal_port['subnet']['cidr'])
+                # we need to add the port's subnet to this internal_port's
+                # allowed_subnet_pool
+                iport_allow_pname = \
+                    self._get_ippool_name(internal_port['mac_address'], '0')
+                ri.ipfilters_manager.add_ippool(iport_allow_pname,
+                                                [port_subnet])
+            else:
+                block_subnets.append(internal_port['subnet']['cidr'])
+                iport_block_pname = \
+                    self._get_ippool_name(internal_port['mac_address'])
+                ri.ipfilters_manager.add_ippool(iport_block_pname,
+                                                [port_subnet])
+        # update the new port's pool with other ports' subnet
+        ri.ipfilters_manager.add_ippool(block_pname, block_subnets)
+        if self.conf.allow_forwarding_between_networks:
+            ri.ipfilters_manager.add_ippool(allow_pname, allow_subnets)
 
-        # now setup the IPF rule
+        # now setup the IPF rules
         rules = ['block in quick on %s from %s to pool/%d' %
-                 (internal_dlname, subnet_cidr, new_ippool_name)]
-        ipversion = netaddr.IPNetwork(subnet_cidr).version
+                 (internal_dlname, port_subnet, block_pname)]
+        # pass in packets between networks that belong to same tenant
+        if self.conf.allow_forwarding_between_networks:
+            rules.append('pass in quick on %s from %s to pool/%d' %
+                         (internal_dlname, port_subnet, allow_pname))
+        # if the external gateway is already setup for the shared router,
+        # then we need to add Policy Based Routing (PBR) for this internal
+        # network
+        ex_gw_port = ri.ex_gw_port
+        ex_gw_ip = (ex_gw_port['subnet']['gateway_ip'] if ex_gw_port else None)
+        if ex_gw_ip:
+            external_dlname = self.get_external_device_name(ex_gw_port['id'])
+            rules.append('pass in on %s to %s:%s from any to any' %
+                         (internal_dlname, external_dlname, ex_gw_ip))
+
+        ipversion = netaddr.IPNetwork(port_subnet).version
         ri.ipfilters_manager.add_ipf_rules(rules, ipversion)
 
     def internal_network_removed(self, ri, port):
         internal_dlname = self.get_internal_device_name(port['id'])
+        port_subnet = port['subnet']['cidr']
+        # remove all the IP filter rules that we added during
+        # internal network addition
+        block_pname = self._get_ippool_name(port['mac_address'])
+        rules = ['block in quick on %s from %s to pool/%d' %
+                 (internal_dlname, port_subnet, block_pname)]
+        if self.conf.allow_forwarding_between_networks:
+            allow_pname = self._get_ippool_name(port['mac_address'], '0')
+            rules.append('pass in quick on %s from %s to pool/%d' %
+                         (internal_dlname, port_subnet, allow_pname))
+
+        # remove all the IP filter rules that we added during
+        # external network addition
+        ex_gw_port = ri.ex_gw_port
+        ex_gw_ip = (ex_gw_port['subnet']['gateway_ip'] if ex_gw_port else None)
+        if ex_gw_ip:
+            external_dlname = self.get_external_device_name(ex_gw_port['id'])
+            rules.append('pass in on %s to %s:%s from any to any' %
+                         (internal_dlname, external_dlname, ex_gw_ip))
+        ipversion = netaddr.IPNetwork(port['subnet']['cidr']).version
+        ri.ipfilters_manager.remove_ipf_rules(rules, ipversion)
+
+        # remove the ippool
+        ri.ipfilters_manager.remove_ippool(block_pname, None)
+        if self.conf.allow_forwarding_between_networks:
+            ri.ipfilters_manager.remove_ippool(allow_pname, None)
+
+        for internal_port in ri.internal_ports:
+            if (self.conf.allow_forwarding_between_networks and
+                    internal_port['tenant_id'] == port['tenant_id']):
+                iport_allow_pname = \
+                    self._get_ippool_name(internal_port['mac_address'], '0')
+                ri.ipfilters_manager.remove_ippool(iport_allow_pname,
+                                                   [port_subnet])
+            else:
+                iport_block_pname = \
+                    self._get_ippool_name(internal_port['mac_address'])
+                ri.ipfilters_manager.remove_ippool(iport_block_pname,
+                                                   [port_subnet])
+
         if net_lib.Datalink.datalink_exists(internal_dlname):
             self.driver.fini_l3(internal_dlname)
             self.driver.unplug(internal_dlname)
 
-        # remove all the IP filter rules that we added during addition.
-        ippool_name = self._get_ippool_name(port['mac_address'])
-        rules = ['block in quick on %s from %s to pool/%d' %
-                 (internal_dlname, port['subnet']['cidr'], ippool_name)]
-        ipversion = netaddr.IPNetwork(port['subnet']['cidr']).version
-        ri.ipfilters_manager.remove_ipf_rules(rules, ipversion)
-        # remove the ippool
-        ri.ipfilters_manager.remove_ippool(ippool_name, None)
-        for internal_port in ri.internal_ports:
-            if (self.conf.allow_forwarding_between_networks and
-                    internal_port['tenant_id'] == port['tenant_id']):
-                continue
-            ippool_name = \
-                self._get_ippool_name(internal_port['mac_address'])
-            subnet_cidr = internal_port['subnet']['cidr']
-            ri.ipfilters_manager.remove_ippool(ippool_name, [subnet_cidr])
-
     def routers_updated(self, context, routers):
         super(EVSL3NATAgent, self).routers_updated(context, routers)
         if routers: