diff --git a/charm-helpers-sync.yaml b/charm-helpers-sync.yaml index 9b5e79e9..755e5ae1 100644 --- a/charm-helpers-sync.yaml +++ b/charm-helpers-sync.yaml @@ -1,4 +1,4 @@ -branch: lp:charm-helpers +branch: lp:~cts-engineering/charm-helpers/neutron-mtu destination: hooks/charmhelpers include: - core diff --git a/hooks/charmhelpers/contrib/network/ip.py b/hooks/charmhelpers/contrib/network/ip.py index 98b17544..a84beb3d 100644 --- a/hooks/charmhelpers/contrib/network/ip.py +++ b/hooks/charmhelpers/contrib/network/ip.py @@ -23,7 +23,14 @@ from functools import partial from charmhelpers.core.hookenv import unit_get from charmhelpers.fetch import apt_install from charmhelpers.core.hookenv import ( - log + config, + log, + INFO +) +from charmhelpers.core.host import ( + list_nics, + get_nic_mtu, + set_nic_mtu ) try: @@ -365,3 +372,26 @@ def is_bridge_member(nic): return True return False + + +def configure_phy_nic_mtu(mng_ip=None): + """Configure mtu for physical nic.""" + phy_nic_mtu = config('phy-nic-mtu') + if phy_nic_mtu >= 1500: + phy_nic = None + if mng_ip is None: + mng_ip = unit_get('private-address') + for nic in list_nics(['eth', 'bond', 'br']): + if mng_ip in get_ipv4_addr(nic, fatal=False): + phy_nic = nic + # need to find the associated phy nic for bridge + if nic.startswith('br'): + for brnic in get_bridge_nics(nic): + if brnic.startswith('eth') or brnic.startswith('bond'): + phy_nic = brnic + break + break + if phy_nic is not None and phy_nic_mtu != get_nic_mtu(phy_nic): + set_nic_mtu(phy_nic, str(phy_nic_mtu), persistence=True) + log('set mtu={} for phy_nic={}' + .format(phy_nic_mtu, phy_nic), level=INFO) diff --git a/hooks/charmhelpers/core/host.py b/hooks/charmhelpers/core/host.py index cf2cbe14..2ec26b0a 100644 --- a/hooks/charmhelpers/core/host.py +++ b/hooks/charmhelpers/core/host.py @@ -361,7 +361,7 @@ def list_nics(nic_type): ip_output = (line for line in ip_output if line) for line in ip_output: if line.split()[1].startswith(int_type): - matched = re.search('.*: (bond[0-9]+\.[0-9]+)@.*', line) + matched = re.search('.*: (' + int_type + r'[0-9]+\.[0-9]+)@.*', line) if matched: interface = matched.groups()[0] else: @@ -371,10 +371,40 @@ def list_nics(nic_type): return interfaces -def set_nic_mtu(nic, mtu): +def set_nic_mtu(nic, mtu, persistence=False): '''Set MTU on a network interface''' cmd = ['ip', 'link', 'set', nic, 'mtu', mtu] subprocess.check_call(cmd) + # persistence mtu configuration + if not persistence: + return + if os.path.exists("/etc/network/interfaces.d/%s.cfg" % nic): + nic_cfg_file = "/etc/network/interfaces.d/%s.cfg" % nic + else: + nic_cfg_file = "/etc/network/interfaces" + + f = open(nic_cfg_file, "r") + lines = f.readlines() + found = False + length = len(lines) + for i in range(len(lines)): + lines[i] = lines[i].replace('\n', '') + if lines[i].startswith("iface %s" % nic): + found = True + lines.insert(i + 1, " up ip link set $IFACE mtu %s" % mtu) + lines.insert(i + 2, " down ip link set $IFACE mtu 1500") + if length > i + 2 and lines[i + 3].startswith(" up ip link set $IFACE mtu"): + del lines[i + 3] + if length > i + 2 and lines[i + 3].startswith(" down ip link set $IFACE mtu"): + del lines[i + 3] + break + if not found: + lines.insert(length + 1, "") + lines.insert(length + 2, "auto %s" % nic) + lines.insert(length + 3, "iface %s inet dhcp" % nic) + lines.insert(length + 4, " up ip link set $IFACE mtu %s" % mtu) + lines.insert(length + 5, " down ip link set $IFACE mtu 1500") + write_file(path=nic_cfg_file, content="\n".join(lines), perms=0o644) def get_nic_mtu(nic): diff --git a/hooks/charmhelpers/core/sysctl.py b/hooks/charmhelpers/core/sysctl.py index d642a371..8e1b9eeb 100644 --- a/hooks/charmhelpers/core/sysctl.py +++ b/hooks/charmhelpers/core/sysctl.py @@ -26,25 +26,31 @@ from subprocess import check_call from charmhelpers.core.hookenv import ( log, DEBUG, + ERROR, ) def create(sysctl_dict, sysctl_file): """Creates a sysctl.conf file from a YAML associative array - :param sysctl_dict: a dict of sysctl options eg { 'kernel.max_pid': 1337 } - :type sysctl_dict: dict + :param sysctl_dict: a YAML-formatted string of sysctl options eg "{ 'kernel.max_pid': 1337 }" + :type sysctl_dict: str :param sysctl_file: path to the sysctl file to be saved :type sysctl_file: str or unicode :returns: None """ - sysctl_dict = yaml.load(sysctl_dict) + try: + sysctl_dict_parsed = yaml.safe_load(sysctl_dict) + except yaml.YAMLError: + log("Error parsing YAML sysctl_dict: {}".format(sysctl_dict), + level=ERROR) + return with open(sysctl_file, "w") as fd: - for key, value in sysctl_dict.items(): + for key, value in sysctl_dict_parsed.items(): fd.write("{}={}\n".format(key, value)) - log("Updating sysctl_file: %s values: %s" % (sysctl_file, sysctl_dict), + log("Updating sysctl_file: %s values: %s" % (sysctl_file, sysctl_dict_parsed), level=DEBUG) check_call(["sysctl", "-p", sysctl_file]) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 7dbf5211..669d3db4 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -26,6 +26,7 @@ def _neutron_api_settings(): 'neutron_security_groups': False, 'l2_population': True, 'overlay_network_type': 'gre', + 'network_device_mtu': 1500, } for rid in relation_ids('neutron-plugin-api'): for unit in related_units(rid): @@ -36,6 +37,8 @@ def _neutron_api_settings(): 'l2_population': rdata['l2-population'], 'neutron_security_groups': rdata['neutron-security-groups'], 'overlay_network_type': rdata['overlay-network-type'], + 'network_device_mtu': rdata['network-device-mtu'] + if 'network-device-mtu' in rdata else 1500, } # Override with configuration if set to true if config('disable-security-groups'): @@ -103,6 +106,8 @@ class OVSPluginContext(context.NeutronContext): neutron_api_settings = _neutron_api_settings() ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups ovs_ctxt['l2_population'] = neutron_api_settings['l2_population'] + ovs_ctxt['network_device_mtu'] = \ + neutron_api_settings['network_device_mtu'] ovs_ctxt['overlay_network_type'] = \ neutron_api_settings['overlay_network_type'] # TODO: We need to sort out the syslog and debug/verbose options as a diff --git a/templates/icehouse/neutron.conf b/templates/icehouse/neutron.conf index 964f6dce..c7af465a 100644 --- a/templates/icehouse/neutron.conf +++ b/templates/icehouse/neutron.conf @@ -1,4 +1,4 @@ -# grizzly +# icehouse ############################################################################### # [ WARNING ] # Configuration file maintained by Juju. Local changes may be overwritten. @@ -12,6 +12,7 @@ state_path = /var/lib/neutron lock_path = $state_path/lock bind_host = 0.0.0.0 bind_port = 9696 +network_device_mtu = {{ network_device_mtu }} {% if core_plugin -%} core_plugin = {{ core_plugin }} diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index 3e2ee906..a94b79ee 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -90,6 +90,7 @@ class OVSPluginContextTest(CharmTestCase): self.relation_ids.return_value = ['rid2'] self.test_relation.set({'neutron-security-groups': True, 'l2-population': True, + 'network-device-mtu': 1500, 'overlay-network-type': 'gre', }) self.get_host_ip.return_value = '127.0.0.15' @@ -100,6 +101,7 @@ class OVSPluginContextTest(CharmTestCase): 'neutron_security_groups': True, 'verbose': True, 'local_ip': '127.0.0.15', + 'network_device_mtu': 1500, 'config': 'neutron.randomconfig', 'use_syslog': True, 'network_manager': 'neutron', @@ -143,6 +145,7 @@ class OVSPluginContextTest(CharmTestCase): self.relation_ids.return_value = ['rid2'] self.test_relation.set({'neutron-security-groups': True, 'l2-population': True, + 'network-device-mtu': 1500, 'overlay-network-type': 'gre', }) self.get_host_ip.return_value = '127.0.0.15' @@ -153,6 +156,7 @@ class OVSPluginContextTest(CharmTestCase): 'neutron_security_groups': False, 'verbose': True, 'local_ip': '127.0.0.15', + 'network_device_mtu': 1500, 'config': 'neutron.randomconfig', 'use_syslog': True, 'network_manager': 'neutron',