|
1 # vim: tabstop=4 shiftwidth=4 softtabstop=4 |
|
2 |
|
3 # Copyright 2014 OpenStack Foundation |
|
4 # All Rights Reserved. |
|
5 # |
|
6 # Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. |
|
7 # |
|
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may |
|
9 # not use this file except in compliance with the License. You may obtain |
|
10 # a copy of the License at |
|
11 # |
|
12 # http://www.apache.org/licenses/LICENSE-2.0 |
|
13 # |
|
14 # Unless required by applicable law or agreed to in writing, software |
|
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
|
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
|
17 # License for the specific language governing permissions and limitations |
|
18 # under the License. |
|
19 |
|
20 import jinja2 |
|
21 import netaddr |
|
22 from oslo.config import cfg |
|
23 import six |
|
24 |
|
25 from neutron.agent.linux import utils |
|
26 from neutron.common import constants |
|
27 from neutron.openstack.common import log as logging |
|
28 |
|
29 |
|
30 LOG = logging.getLogger(__name__) |
|
31 |
|
32 OPTS = [ |
|
33 cfg.StrOpt('ra_confs', |
|
34 default='$state_path/ra', |
|
35 help=_('Location to store IPv6 RA config files')), |
|
36 ] |
|
37 |
|
38 cfg.CONF.register_opts(OPTS) |
|
39 |
|
40 NDP_SMF_FMRI = 'svc:/network/routing/ndp:default' |
|
41 |
|
42 CONFIG_TEMPLATE = jinja2.Template("""if {{ interface_name }} \ |
|
43 AdvSendAdvertisements on \ |
|
44 MinRtrAdvInterval 3 \ |
|
45 MaxRtrAdvInterval 10 \ |
|
46 {% if ra_mode == constants.DHCPV6_STATELESS %} |
|
47 AdvOtherConfigFlag on \ |
|
48 {% endif %} |
|
49 |
|
50 {% if ra_mode == constants.DHCPV6_STATEFUL %} |
|
51 AdvManagedFlag on |
|
52 {% endif %} |
|
53 |
|
54 {% if ra_mode in (constants.IPV6_SLAAC, constants.DHCPV6_STATELESS) %} |
|
55 prefix {{ prefix }} {{ interface_name }} \ |
|
56 AdvOnLinkFlag on \ |
|
57 AdvAutonomousFlag on |
|
58 {% endif %} |
|
59 """) |
|
60 |
|
61 |
|
62 def _generate_ndpd_conf(router_id, router_ports, dev_name_helper): |
|
63 ndpd_conf = utils.get_conf_file_name(cfg.CONF.ra_confs, router_id, |
|
64 'ndpd.conf', True) |
|
65 buf = six.StringIO() |
|
66 for p in router_ports: |
|
67 prefix = p['subnet']['cidr'] |
|
68 if netaddr.IPNetwork(prefix).version == 6: |
|
69 interface_name = dev_name_helper(p['id']) |
|
70 ra_mode = p['subnet']['ipv6_ra_mode'] |
|
71 buf.write('%s' % CONFIG_TEMPLATE.render( |
|
72 ra_mode=ra_mode, |
|
73 interface_name=interface_name, |
|
74 prefix=prefix, |
|
75 constants=constants)) |
|
76 |
|
77 utils.replace_file(ndpd_conf, buf.getvalue()) |
|
78 return ndpd_conf |
|
79 |
|
80 |
|
81 def _refresh_ndpd(ndpd_conf): |
|
82 cmd = ['/usr/sbin/svccfg', '-s', NDP_SMF_FMRI, 'setprop', |
|
83 'routing/config_file', '=', ndpd_conf] |
|
84 utils.execute(cmd) |
|
85 # ndpd SMF service doesn't support refresh method, so we |
|
86 # need to restart |
|
87 cmd = ['/usr/sbin/svcadm', 'restart', NDP_SMF_FMRI] |
|
88 utils.execute(cmd) |
|
89 LOG.debug(_("ndpd daemon has been refreshed to re-read the " |
|
90 "configuration file")) |
|
91 |
|
92 |
|
93 def enable_ipv6_ra(router_id, router_ports, dev_name_helper): |
|
94 for p in router_ports: |
|
95 if netaddr.IPNetwork(p['subnet']['cidr']).version == 6: |
|
96 break |
|
97 else: |
|
98 disable_ipv6_ra(router_id) |
|
99 return |
|
100 LOG.debug("enabling ndpd for router %s", router_id) |
|
101 ndpd_conf = _generate_ndpd_conf(router_id, router_ports, dev_name_helper) |
|
102 _refresh_ndpd(ndpd_conf) |
|
103 |
|
104 |
|
105 def disable_ipv6_ra(router_id): |
|
106 LOG.debug("disabling ndpd for router %s", router_id) |
|
107 utils.remove_conf_files(cfg.CONF.ra_confs, router_id) |
|
108 _refresh_ndpd("") |