|
1 In-house patch to split out the Linux specific implementation details of the |
|
2 Neutron DHCP agent into a separate module. This allows for a common |
|
3 main DHCP agent module on different platforms. This patch has not yet |
|
4 been submitted upstream. |
|
5 |
|
6 --- quantum-2013.1.4/quantum/agent/dhcp_agent.py.~1~ 2013-10-17 11:24:18.000000000 -0700 |
|
7 +++ quantum-2013.1.4/quantum/agent/dhcp_agent.py 2014-03-13 01:37:26.539103862 -0700 |
|
8 @@ -17,7 +17,6 @@ |
|
9 |
|
10 import os |
|
11 import socket |
|
12 -import uuid |
|
13 |
|
14 import eventlet |
|
15 import netaddr |
|
16 @@ -26,11 +25,8 @@ |
|
17 from quantum.agent.common import config |
|
18 from quantum.agent.linux import dhcp |
|
19 from quantum.agent.linux import external_process |
|
20 -from quantum.agent.linux import interface |
|
21 -from quantum.agent.linux import ip_lib |
|
22 from quantum.agent import rpc as agent_rpc |
|
23 from quantum.common import constants |
|
24 -from quantum.common import exceptions |
|
25 from quantum.common import topics |
|
26 from quantum import context |
|
27 from quantum import manager |
|
28 @@ -58,6 +54,9 @@ |
|
29 cfg.StrOpt('dhcp_driver', |
|
30 default='quantum.agent.linux.dhcp.Dnsmasq', |
|
31 help=_("The driver used to manage the DHCP server.")), |
|
32 + cfg.StrOpt('devicemanager', |
|
33 + default='quantum.agent.linux.device.DeviceManager', |
|
34 + help=_("The driver to manage OS specific devices.")), |
|
35 cfg.BoolOpt('use_namespaces', default=True, |
|
36 help=_("Allow overlapping IP.")), |
|
37 cfg.BoolOpt('enable_isolated_metadata', default=False, |
|
38 @@ -77,7 +76,9 @@ |
|
39 self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver) |
|
40 ctx = context.get_admin_context_without_session() |
|
41 self.plugin_rpc = DhcpPluginApi(topics.PLUGIN, ctx) |
|
42 - self.device_manager = DeviceManager(self.conf, self.plugin_rpc) |
|
43 + self.device_manager = \ |
|
44 + importutils.import_object(self.conf.devicemanager, |
|
45 + self.conf, self.plugin_rpc) |
|
46 self.lease_relay = DhcpLeaseRelay(self.update_lease) |
|
47 |
|
48 self.dhcp_version = self.dhcp_driver_cls.check_version() |
|
49 @@ -494,167 +495,6 @@ |
|
50 'ports': num_ports} |
|
51 |
|
52 |
|
53 -class DeviceManager(object): |
|
54 - OPTS = [ |
|
55 - cfg.StrOpt('interface_driver', |
|
56 - help=_("The driver used to manage the virtual interface.")) |
|
57 - ] |
|
58 - |
|
59 - def __init__(self, conf, plugin): |
|
60 - self.conf = conf |
|
61 - self.root_helper = config.get_root_helper(conf) |
|
62 - self.plugin = plugin |
|
63 - if not conf.interface_driver: |
|
64 - raise SystemExit(_('You must specify an interface driver')) |
|
65 - try: |
|
66 - self.driver = importutils.import_object(conf.interface_driver, |
|
67 - conf) |
|
68 - except: |
|
69 - msg = _("Error importing interface driver " |
|
70 - "'%s'") % conf.interface_driver |
|
71 - raise SystemExit(msg) |
|
72 - |
|
73 - def get_interface_name(self, network, port=None): |
|
74 - """Return interface(device) name for use by the DHCP process.""" |
|
75 - if not port: |
|
76 - device_id = self.get_device_id(network) |
|
77 - port = self.plugin.get_dhcp_port(network.id, device_id) |
|
78 - return self.driver.get_device_name(port) |
|
79 - |
|
80 - def get_device_id(self, network): |
|
81 - """Return a unique DHCP device ID for this host on the network.""" |
|
82 - # There could be more than one dhcp server per network, so create |
|
83 - # a device id that combines host and network ids |
|
84 - |
|
85 - host_uuid = uuid.uuid5(uuid.NAMESPACE_DNS, socket.gethostname()) |
|
86 - return 'dhcp%s-%s' % (host_uuid, network.id) |
|
87 - |
|
88 - def _get_device(self, network): |
|
89 - """Return DHCP ip_lib device for this host on the network.""" |
|
90 - device_id = self.get_device_id(network) |
|
91 - port = self.plugin.get_dhcp_port(network.id, device_id) |
|
92 - interface_name = self.get_interface_name(network, port) |
|
93 - namespace = NS_PREFIX + network.id |
|
94 - return ip_lib.IPDevice(interface_name, |
|
95 - self.root_helper, |
|
96 - namespace) |
|
97 - |
|
98 - def _set_default_route(self, network): |
|
99 - """Sets the default gateway for this dhcp namespace. |
|
100 - |
|
101 - This method is idempotent and will only adjust the route if adjusting |
|
102 - it would change it from what it already is. This makes it safe to call |
|
103 - and avoids unnecessary perturbation of the system. |
|
104 - """ |
|
105 - device = self._get_device(network) |
|
106 - gateway = device.route.get_gateway() |
|
107 - |
|
108 - for subnet in network.subnets: |
|
109 - skip_subnet = ( |
|
110 - subnet.ip_version != 4 |
|
111 - or not subnet.enable_dhcp |
|
112 - or subnet.gateway_ip is None) |
|
113 - |
|
114 - if skip_subnet: |
|
115 - continue |
|
116 - |
|
117 - if gateway != subnet.gateway_ip: |
|
118 - m = _('Setting gateway for dhcp netns on net %(n)s to %(ip)s') |
|
119 - LOG.debug(m, {'n': network.id, 'ip': subnet.gateway_ip}) |
|
120 - |
|
121 - device.route.add_gateway(subnet.gateway_ip) |
|
122 - |
|
123 - return |
|
124 - |
|
125 - # No subnets on the network have a valid gateway. Clean it up to avoid |
|
126 - # confusion from seeing an invalid gateway here. |
|
127 - if gateway is not None: |
|
128 - msg = _('Removing gateway for dhcp netns on net %s') |
|
129 - LOG.debug(msg, network.id) |
|
130 - |
|
131 - device.route.delete_gateway(gateway) |
|
132 - |
|
133 - def setup(self, network, reuse_existing=False): |
|
134 - """Create and initialize a device for network's DHCP on this host.""" |
|
135 - device_id = self.get_device_id(network) |
|
136 - port = self.plugin.get_dhcp_port(network.id, device_id) |
|
137 - |
|
138 - interface_name = self.get_interface_name(network, port) |
|
139 - |
|
140 - if self.conf.use_namespaces: |
|
141 - namespace = NS_PREFIX + network.id |
|
142 - else: |
|
143 - namespace = None |
|
144 - |
|
145 - if ip_lib.device_exists(interface_name, |
|
146 - self.root_helper, |
|
147 - namespace): |
|
148 - if not reuse_existing: |
|
149 - raise exceptions.PreexistingDeviceFailure( |
|
150 - dev_name=interface_name) |
|
151 - |
|
152 - LOG.debug(_('Reusing existing device: %s.'), interface_name) |
|
153 - else: |
|
154 - self.driver.plug(network.id, |
|
155 - port.id, |
|
156 - interface_name, |
|
157 - port.mac_address, |
|
158 - namespace=namespace) |
|
159 - ip_cidrs = [] |
|
160 - for fixed_ip in port.fixed_ips: |
|
161 - subnet = fixed_ip.subnet |
|
162 - net = netaddr.IPNetwork(subnet.cidr) |
|
163 - ip_cidr = '%s/%s' % (fixed_ip.ip_address, net.prefixlen) |
|
164 - ip_cidrs.append(ip_cidr) |
|
165 - |
|
166 - if (self.conf.enable_isolated_metadata and |
|
167 - self.conf.use_namespaces): |
|
168 - ip_cidrs.append(METADATA_DEFAULT_IP) |
|
169 - |
|
170 - self.driver.init_l3(interface_name, ip_cidrs, |
|
171 - namespace=namespace) |
|
172 - |
|
173 - # ensure that the dhcp interface is first in the list |
|
174 - if namespace is None: |
|
175 - device = ip_lib.IPDevice(interface_name, |
|
176 - self.root_helper) |
|
177 - device.route.pullup_route(interface_name) |
|
178 - |
|
179 - if self.conf.enable_metadata_network: |
|
180 - meta_cidr = netaddr.IPNetwork(METADATA_DEFAULT_IP) |
|
181 - metadata_subnets = [s for s in network.subnets if |
|
182 - netaddr.IPNetwork(s.cidr) in meta_cidr] |
|
183 - if metadata_subnets: |
|
184 - # Add a gateway so that packets can be routed back to VMs |
|
185 - device = ip_lib.IPDevice(interface_name, |
|
186 - self.root_helper, |
|
187 - namespace) |
|
188 - # Only 1 subnet on metadata access network |
|
189 - gateway_ip = metadata_subnets[0].gateway_ip |
|
190 - device.route.add_gateway(gateway_ip) |
|
191 - elif self.conf.use_namespaces: |
|
192 - self._set_default_route(network) |
|
193 - |
|
194 - return interface_name |
|
195 - |
|
196 - def update(self, network): |
|
197 - """Update device settings for the network's DHCP on this host.""" |
|
198 - if self.conf.use_namespaces and not self.conf.enable_metadata_network: |
|
199 - self._set_default_route(network) |
|
200 - |
|
201 - def destroy(self, network, device_name): |
|
202 - """Destroy the device used for the network's DHCP on this host.""" |
|
203 - if self.conf.use_namespaces: |
|
204 - namespace = NS_PREFIX + network.id |
|
205 - else: |
|
206 - namespace = None |
|
207 - |
|
208 - self.driver.unplug(device_name, namespace=namespace) |
|
209 - |
|
210 - self.plugin.release_dhcp_port(network.id, |
|
211 - self.get_device_id(network)) |
|
212 - |
|
213 - |
|
214 class DictModel(object): |
|
215 """Convert dict into an object that provides attribute access to values.""" |
|
216 def __init__(self, d): |
|
217 @@ -783,11 +623,11 @@ |
|
218 cfg.CONF.register_opts(DhcpAgent.OPTS) |
|
219 config.register_agent_state_opts_helper(cfg.CONF) |
|
220 config.register_root_helper(cfg.CONF) |
|
221 - cfg.CONF.register_opts(DeviceManager.OPTS) |
|
222 cfg.CONF.register_opts(DhcpLeaseRelay.OPTS) |
|
223 cfg.CONF.register_opts(dhcp.OPTS) |
|
224 - cfg.CONF.register_opts(interface.OPTS) |
|
225 cfg.CONF(project='quantum') |
|
226 + if not cfg.CONF.devicemanager: |
|
227 + raise SystemExit(_('You must specify a devicemanager')) |
|
228 config.setup_logging(cfg.CONF) |
|
229 server = quantum_service.Service.create( |
|
230 binary='quantum-dhcp-agent', |
|
231 --- quantum-2013.1.4/quantum/db/dhcp_rpc_base.py.~1~ 2013-10-17 11:24:18.000000000 -0700 |
|
232 +++ quantum-2013.1.4/quantum/db/dhcp_rpc_base.py 2014-03-13 01:27:46.731450967 -0700 |
|
233 @@ -97,11 +97,14 @@ |
|
234 for fixed_ip in port['fixed_ips']: |
|
235 if fixed_ip['subnet_id'] in dhcp_enabled_subnet_ids: |
|
236 dhcp_enabled_subnet_ids.remove(fixed_ip['subnet_id']) |
|
237 - port['fixed_ips'].extend( |
|
238 - [dict(subnet_id=s) for s in dhcp_enabled_subnet_ids]) |
|
239 + if dhcp_enabled_subnet_ids: |
|
240 + port['fixed_ips'].extend( |
|
241 + [dict(subnet_id=s) for s in dhcp_enabled_subnet_ids]) |
|
242 |
|
243 - retval = plugin.update_port(context, port['id'], |
|
244 - dict(port=port)) |
|
245 + retval = plugin.update_port(context, port['id'], |
|
246 + dict(port=port)) |
|
247 + else: |
|
248 + retval = port |
|
249 |
|
250 except exc.NoResultFound: |
|
251 pass |