Set lock_path correctly.
[openstack-build/neutron-build.git] / neutron / agent / l3 / dvr_edge_router.py
1 # Copyright (c) 2015 Openstack Foundation
2 #
3 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
4 #    not use this file except in compliance with the License. You may obtain
5 #    a copy of the License at
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
9 #    Unless required by applicable law or agreed to in writing, software
10 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 #    License for the specific language governing permissions and limitations
13 #    under the License.
14
15 from oslo_log import log as logging
16
17 from neutron._i18n import _LE
18 from neutron.agent.l3 import dvr_local_router
19 from neutron.agent.l3 import dvr_snat_ns
20 from neutron.agent.l3 import router_info as router
21 from neutron.agent.linux import ip_lib
22 from neutron.agent.linux import iptables_manager
23
24 LOG = logging.getLogger(__name__)
25
26
27 class DvrEdgeRouter(dvr_local_router.DvrLocalRouter):
28
29     def __init__(self, agent, host, *args, **kwargs):
30         super(DvrEdgeRouter, self).__init__(agent, host, *args, **kwargs)
31         self.snat_namespace = None
32         self.snat_iptables_manager = None
33
34     def external_gateway_added(self, ex_gw_port, interface_name):
35         super(DvrEdgeRouter, self).external_gateway_added(
36             ex_gw_port, interface_name)
37         if self._is_this_snat_host():
38             self._create_dvr_gateway(ex_gw_port, interface_name)
39             # NOTE: When a router is created without a gateway the routes get
40             # added to the router namespace, but if we wanted to populate
41             # the same routes to the snat namespace after the gateway port
42             # is added, we need to call routes_updated here.
43             self.routes_updated([], self.router['routes'])
44
45     def external_gateway_updated(self, ex_gw_port, interface_name):
46         if not self._is_this_snat_host():
47             # no centralized SNAT gateway for this node/agent
48             LOG.debug("not hosting snat for router: %s", self.router['id'])
49             if self.snat_namespace:
50                 LOG.debug("SNAT was rescheduled to host %s. Clearing snat "
51                           "namespace.", self.router.get('gw_port_host'))
52                 return self.external_gateway_removed(
53                     ex_gw_port, interface_name)
54             return
55
56         if not self.snat_namespace:
57             # SNAT might be rescheduled to this agent; need to process like
58             # newly created gateway
59             return self.external_gateway_added(ex_gw_port, interface_name)
60         else:
61             self._external_gateway_added(ex_gw_port,
62                                         interface_name,
63                                         self.snat_namespace.name,
64                                         preserve_ips=[])
65
66     def _external_gateway_removed(self, ex_gw_port, interface_name):
67         super(DvrEdgeRouter, self).external_gateway_removed(ex_gw_port,
68                                                             interface_name)
69         if not self._is_this_snat_host() and not self.snat_namespace:
70             # no centralized SNAT gateway for this node/agent
71             LOG.debug("not hosting snat for router: %s", self.router['id'])
72             return
73
74         self.driver.unplug(interface_name,
75                            bridge=self.agent_conf.external_network_bridge,
76                            namespace=self.snat_namespace.name,
77                            prefix=router.EXTERNAL_DEV_PREFIX)
78
79     def external_gateway_removed(self, ex_gw_port, interface_name):
80         self._external_gateway_removed(ex_gw_port, interface_name)
81         if self.snat_namespace:
82             self.snat_namespace.delete()
83             self.snat_namespace = None
84
85     def internal_network_added(self, port):
86         super(DvrEdgeRouter, self).internal_network_added(port)
87
88         # TODO(gsagie) some of this checks are already implemented
89         # in the base class, think how to avoid re-doing them
90         if not self._is_this_snat_host():
91             return
92
93         sn_port = self.get_snat_port_for_internal_port(port)
94         if not sn_port:
95             return
96
97         ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(self.router['id'])
98         interface_name = self._get_snat_int_device_name(sn_port['id'])
99         self._internal_network_added(
100             ns_name,
101             sn_port['network_id'],
102             sn_port['id'],
103             sn_port['fixed_ips'],
104             sn_port['mac_address'],
105             interface_name,
106             dvr_snat_ns.SNAT_INT_DEV_PREFIX)
107
108     def _dvr_internal_network_removed(self, port):
109         super(DvrEdgeRouter, self)._dvr_internal_network_removed(port)
110
111         if not self.ex_gw_port:
112             return
113
114         sn_port = self.get_snat_port_for_internal_port(port, self.snat_ports)
115         if not sn_port:
116             return
117
118         if not self._is_this_snat_host():
119             return
120
121         snat_interface = self._get_snat_int_device_name(sn_port['id'])
122         ns_name = self.snat_namespace.name
123         prefix = dvr_snat_ns.SNAT_INT_DEV_PREFIX
124         if ip_lib.device_exists(snat_interface, namespace=ns_name):
125             self.driver.unplug(snat_interface, namespace=ns_name,
126                                prefix=prefix)
127
128     def _plug_snat_port(self, port):
129         interface_name = self._get_snat_int_device_name(port['id'])
130         self._internal_network_added(
131             self.snat_namespace.name, port['network_id'],
132             port['id'], port['fixed_ips'],
133             port['mac_address'], interface_name,
134             dvr_snat_ns.SNAT_INT_DEV_PREFIX)
135
136     def _create_dvr_gateway(self, ex_gw_port, gw_interface_name):
137         """Create SNAT namespace."""
138         snat_ns = self._create_snat_namespace()
139         # connect snat_ports to br_int from SNAT namespace
140         for port in self.get_snat_interfaces():
141             # create interface_name
142             self._plug_snat_port(port)
143         self._external_gateway_added(ex_gw_port, gw_interface_name,
144                                      snat_ns.name, preserve_ips=[])
145         self.snat_iptables_manager = iptables_manager.IptablesManager(
146             namespace=snat_ns.name,
147             use_ipv6=self.use_ipv6)
148         # kicks the FW Agent to add rules for the snat namespace
149         self.agent.process_router_add(self)
150
151     def _create_snat_namespace(self):
152         # TODO(mlavalle): in the near future, this method should contain the
153         # code in the L3 agent that creates a gateway for a dvr. The first step
154         # is to move the creation of the snat namespace here
155         self.snat_namespace = dvr_snat_ns.SnatNamespace(self.router['id'],
156                                                         self.agent_conf,
157                                                         self.driver,
158                                                         self.use_ipv6)
159         self.snat_namespace.create()
160         return self.snat_namespace
161
162     def _get_snat_int_device_name(self, port_id):
163         long_name = dvr_snat_ns.SNAT_INT_DEV_PREFIX + port_id
164         return long_name[:self.driver.DEV_NAME_LEN]
165
166     def _is_this_snat_host(self):
167         host = self.router.get('gw_port_host')
168         if not host:
169             LOG.debug("gw_port_host missing from router: %s",
170                       self.router['id'])
171         return host == self.host
172
173     def _handle_router_snat_rules(self, ex_gw_port, interface_name):
174         if not self._is_this_snat_host():
175             return
176         if not self.get_ex_gw_port():
177             return
178
179         if not self.snat_iptables_manager:
180             LOG.debug("DVR router: no snat rules to be handled")
181             return
182
183         with self.snat_iptables_manager.defer_apply():
184             self._empty_snat_chains(self.snat_iptables_manager)
185
186             # NOTE DVR doesn't add the jump to float snat like the super class.
187
188             self._add_snat_rules(ex_gw_port, self.snat_iptables_manager,
189                                  interface_name)
190
191     def update_routing_table(self, operation, route):
192         if self.get_ex_gw_port() and self._is_this_snat_host():
193             ns_name = dvr_snat_ns.SnatNamespace.get_snat_ns_name(
194                 self.router['id'])
195             # NOTE: For now let us apply the static routes both in SNAT
196             # namespace and Router Namespace, to reduce the complexity.
197             ip_wrapper = ip_lib.IPWrapper(namespace=ns_name)
198             if ip_wrapper.netns.exists(ns_name):
199                 super(DvrEdgeRouter, self)._update_routing_table(
200                     operation, route, namespace=ns_name)
201             else:
202                 LOG.error(_LE("The SNAT namespace %s does not exist for "
203                               "the router."), ns_name)
204         super(DvrEdgeRouter, self).update_routing_table(operation, route)
205
206     def delete(self, agent):
207         super(DvrEdgeRouter, self).delete(agent)
208         if self.snat_namespace:
209             self.snat_namespace.delete()