2521N/A# vim: tabstop=4 shiftwidth=4 softtabstop=4
2521N/A
5577N/A# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
2521N/A#
2521N/A# Licensed under the Apache License, Version 2.0 (the "License"); you may
2521N/A# not use this file except in compliance with the License. You may obtain
2521N/A# a copy of the License at
2521N/A#
2521N/A# http://www.apache.org/licenses/LICENSE-2.0
2521N/A#
2521N/A# Unless required by applicable law or agreed to in writing, software
2521N/A# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
2521N/A# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2521N/A# License for the specific language governing permissions and limitations
2521N/A# under the License.
2521N/A#
2521N/A# @author: Girish Moodalbail, Oracle, Inc.
2521N/A#
2521N/A
6029N/Aimport eventlet
2763N/Aimport netaddr
2763N/A
6029N/Afrom oslo_log import log as logging
6029N/A
2892N/Afrom neutron.agent.linux import utils
6029N/Afrom neutron.i18n import _LE
6029N/A
6029N/ALOG = logging.getLogger(__name__)
2521N/A
2521N/A
2521N/Aclass CommandBase(object):
2521N/A @classmethod
2521N/A def execute_with_pfexec(cls, cmd, **kwargs):
2521N/A # uses pfexec
2521N/A cmd.insert(0, '/usr/bin/pfexec')
2521N/A return utils.execute(cmd, **kwargs)
2521N/A
2521N/A @classmethod
2521N/A def execute(cls, cmd, **kwargs):
2521N/A return utils.execute(cmd, **kwargs)
2521N/A
2521N/A
2521N/Aclass IPInterface(CommandBase):
2521N/A '''Wrapper around Solaris ipadm(1m) command.'''
2521N/A
2521N/A def __init__(self, ifname):
2521N/A self._ifname = ifname
2521N/A
2521N/A @classmethod
2521N/A def ifname_exists(cls, ifname):
5577N/A try:
5577N/A cmd = ['/usr/sbin/ipadm', 'show-if', '-po', 'ifname', ifname]
5577N/A cls.execute(cmd, log_fail_as_error=False)
5577N/A except Exception:
5577N/A return False
5577N/A return True
2521N/A
2521N/A @classmethod
6846N/A def ipaddr_exists(cls, ipaddr, ifname=None):
6846N/A cmd = ['/usr/sbin/ipadm', 'show-addr', '-po', 'addr']
6846N/A if ifname:
6846N/A cmd.append(ifname)
2521N/A stdout = cls.execute(cmd)
2521N/A
2521N/A return ipaddr in stdout
2521N/A
2521N/A def ipaddr_list(self, filters=None):
2892N/A cmd = ['/usr/sbin/ipadm', 'show-addr', '-po', 'type,addr',
2521N/A self._ifname]
2521N/A stdout = self.execute(cmd)
2521N/A atype_addrs = stdout.strip().split('\n')
2521N/A result = {}
2521N/A for atype_addr in atype_addrs:
2892N/A atype, addr = atype_addr.split(':', 1)
2521N/A val = result.get(atype)
2521N/A if val is None:
2521N/A result[atype] = []
2521N/A val = result.get(atype)
2892N/A # in the case of IPv6 addresses remove any escape '\' character
2892N/A val.append(addr.replace("\\", ""))
2521N/A return result
2521N/A
6553N/A def create_address(self, ipaddr, addrobjname=None, temp=True,
6553N/A ifcheck=True, addrcheck=True):
6553N/A if ifcheck and not self.ifname_exists(self._ifname):
2521N/A # create ip interface
2521N/A cmd = ['/usr/sbin/ipadm', 'create-ip', self._ifname]
2521N/A if temp:
7402N/A cmd.insert(2, '-t')
2521N/A self.execute_with_pfexec(cmd)
6846N/A elif addrcheck and self.ipaddr_exists(ipaddr, self._ifname):
2521N/A return
2521N/A
2763N/A # If an address is IPv6, then to create a static IPv6 address
2763N/A # we need to create link-local address first
2763N/A if netaddr.IPNetwork(ipaddr).version == 6:
2763N/A # check if link-local address already exists
2763N/A cmd = ['/usr/sbin/dladm', 'show-linkprop', '-co', 'value',
2763N/A '-p', 'mac-address', self._ifname]
2763N/A stdout = self.execute(cmd)
2763N/A mac_addr = stdout.splitlines()[0].strip()
2763N/A ll_addr = netaddr.EUI(mac_addr).ipv6_link_local()
2763N/A
6846N/A if addrcheck and not self.ipaddr_exists(str(ll_addr),
6846N/A self._ifname):
2763N/A # create a link-local address
2763N/A cmd = ['/usr/sbin/ipadm', 'create-addr', '-T', 'static', '-a',
2763N/A str(ll_addr), self._ifname]
2763N/A if temp:
7402N/A cmd.insert(2, '-t')
2763N/A self.execute_with_pfexec(cmd)
2763N/A
2763N/A cmd = ['/usr/sbin/ipadm', 'create-addr', '-T', 'static', '-a',
2521N/A ipaddr, self._ifname]
2521N/A if temp:
7402N/A cmd.insert(2, '-t')
2521N/A
3162N/A self.execute_with_pfexec(cmd)
2521N/A
4973N/A def create_addrconf(self, temp=True):
4973N/A if not self.ifname_exists(self._ifname):
4973N/A # create ip interface
4973N/A cmd = ['/usr/sbin/ipadm', 'create-ip', self._ifname]
4973N/A if temp:
7402N/A cmd.insert(2, '-t')
4973N/A self.execute_with_pfexec(cmd)
4973N/A else:
4973N/A cmd = ['/usr/sbin/ipadm', 'show-addr', '-po', 'type', self._ifname]
4973N/A stdout = self.execute(cmd)
4973N/A if 'addrconf' in stdout:
4973N/A return
4973N/A
4973N/A cmd = ['/usr/sbin/ipadm', 'create-addr', '-T', 'addrconf',
4973N/A self._ifname]
4973N/A if temp:
7402N/A cmd.insert(2, '-t')
4973N/A self.execute_with_pfexec(cmd)
4973N/A
6553N/A def delete_address(self, ipaddr, addrcheck=True):
6846N/A if addrcheck and not self.ipaddr_exists(ipaddr, self._ifname):
2521N/A return
2521N/A
2521N/A cmd = ['/usr/sbin/ipadm', 'show-addr', '-po', 'addrobj,addr',
2521N/A self._ifname]
2521N/A stdout = self.execute(cmd)
2521N/A aobj_addrs = stdout.strip().split('\n')
2521N/A for aobj_addr in aobj_addrs:
2521N/A if ipaddr not in aobj_addr:
2521N/A continue
2521N/A aobj = aobj_addr.split(':')[0]
2521N/A cmd = ['/usr/sbin/ipadm', 'delete-addr', aobj]
2521N/A self.execute_with_pfexec(cmd)
2521N/A break
2521N/A
2763N/A isV6 = netaddr.IPNetwork(ipaddr).version == 6
2763N/A if len(aobj_addrs) == 1 or (isV6 and len(aobj_addrs) == 2):
2521N/A # delete the interface as well
2521N/A cmd = ['/usr/sbin/ipadm', 'delete-ip', self._ifname]
2521N/A self.execute_with_pfexec(cmd)
2521N/A
2521N/A def delete_ip(self):
2521N/A if not self.ifname_exists(self._ifname):
2521N/A return
2521N/A
2521N/A cmd = ['/usr/sbin/ipadm', 'delete-ip', self._ifname]
2521N/A self.execute_with_pfexec(cmd)
2521N/A
2521N/A
2521N/Aclass Datalink(CommandBase):
2521N/A '''Wrapper around Solaris dladm(1m) command.'''
2521N/A
2521N/A def __init__(self, dlname):
2521N/A self._dlname = dlname
2521N/A
2521N/A @classmethod
2521N/A def datalink_exists(cls, dlname):
5577N/A try:
5577N/A cmd = ['/usr/sbin/dladm', 'show-link', '-po', 'link', dlname]
5577N/A utils.execute(cmd, log_fail_as_error=False)
5577N/A except Exception:
5577N/A return False
5577N/A return True
2521N/A
2892N/A def create_vnic(self, lower_link, mac_address=None, vid=None, temp=True):
2521N/A if self.datalink_exists(self._dlname):
2521N/A return
2521N/A
2892N/A if vid:
2892N/A # If the default_tag of lower_link is same as vid, then there
2892N/A # is no need to set vid
2892N/A cmd = ['/usr/sbin/dladm', 'show-linkprop', '-co', 'value',
2892N/A '-p', 'default_tag', lower_link]
2892N/A stdout = utils.execute(cmd)
5403N/A default_tag = stdout.splitlines()[0].strip()
5403N/A if default_tag == vid or (vid == '1' and default_tag == '0'):
2892N/A vid = '0'
2892N/A else:
2892N/A vid = '0'
2521N/A cmd = ['/usr/sbin/dladm', 'create-vnic', '-l', lower_link,
2892N/A '-m', mac_address, '-v', vid, self._dlname]
2521N/A if temp:
7402N/A cmd.insert(2, '-t')
2521N/A
3162N/A self.execute_with_pfexec(cmd)
2521N/A
7312N/A def set_prop(self, pname, pvalue, temp=True):
7312N/A cmd = ['/usr/sbin/dladm', 'set-linkprop', '-p', '%s=%s'
7312N/A % (pname, pvalue), self._dlname]
7312N/A if temp:
7402N/A cmd.insert(2, '-t')
7312N/A self.execute_with_pfexec(cmd)
7312N/A
2521N/A def delete_vnic(self):
2521N/A if not self.datalink_exists(self._dlname):
2521N/A return
2521N/A
2521N/A cmd = ['/usr/sbin/dladm', 'delete-vnic', self._dlname]
3162N/A self.execute_with_pfexec(cmd)
2521N/A
3998N/A @classmethod
5577N/A def show_link(cls):
5577N/A cmd = ['/usr/sbin/dladm', 'show-link', '-po', 'link']
3998N/A stdout = utils.execute(cmd)
3998N/A
3998N/A return stdout.splitlines()
6029N/A
6029N/A
6029N/Adef _arping(iface_name, address, count):
6029N/A # Set timeout with -w to ensure arping exits in case the interface
6029N/A # is deleted while it is running
6029N/A arping_cmd = ['/usr/sbin/arping', '-A', '-I', iface_name, '-c', count,
6029N/A '-w', 2 * count, address]
6029N/A try:
6029N/A utils.execute(arping_cmd, check_exit_code=False)
6029N/A except Exception:
6029N/A msg = _LE("Failed sending gratuitous ARP to %(addr)s on "
6029N/A "an interface %(iface)s")
6029N/A LOG.exception(msg, {'addr': address, 'iface': iface_name})
6029N/A
6029N/A
6029N/Adef send_ip_addr_adv_notif(iface_name, address, config):
6029N/A """Send advance notification of an IP address assignment.
6029N/A
6029N/A If the address is in the IPv4 family, send gratuitous ARP.
6029N/A
6029N/A If the address is in the IPv6 family, no advance notification is
6029N/A necessary, since the Neighbor Discovery Protocol (NDP), Duplicate
6029N/A Address Discovery (DAD), and (for stateless addresses) router
6029N/A advertisements (RAs) are sufficient for address resolution and
6029N/A duplicate address detection.
6029N/A """
6029N/A count = config.send_arp_for_ha
6029N/A
6029N/A def arping():
6029N/A _arping(iface_name, address, count)
6029N/A
6029N/A if count > 0 and netaddr.IPAddress(address).version == 4:
6029N/A eventlet.spawn_n(arping)