cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From raj...@apache.org
Subject [1/4] git commit: updated refs/heads/master to f10c8bf
Date Fri, 27 Jan 2017 00:13:41 GMT
Repository: cloudstack
Updated Branches:
  refs/heads/master 4721c53ea -> f10c8bfe0


CLOUDSTACK-9359: IPv6 for Basic Networking with KVM

This commit adds the initial functionality for IPv6 in Basic Networking.

When a valid IPv6 CIDR is configured for the POD/VLAN the DirectPodBasedNetworkGuru
will use the EUI-64 calculation to calculate the IPv6 Address the Instance will obtain.

For this it is required that the physical routers in the Layer 2 network (POD/VLAN) send out
Router Advertisements with the same subnet as configured in CloudStack.

A example subnet could be 2001:db8::/64

Using radvd a Linux Router could send out Router Advertisements using this configuration:

  interface eth0
  {

	MinRtrAdvInterval 5;
	MaxRtrAdvInterval 60;
	AdvSendAdvert on;
        AdvOtherConfigFlag off;
        IgnoreIfMissing off;

	prefix 2001:db8::/64 {
	};

        RDNSS 2001:db8:ffff::53 {
        };
  };

A Instance with MAC Address 06:7a:88:00:00:8b will obtain IPv6 address 2001:db8:100::47a:88ff:fe00:8b

Both Windows, Linux and FreeBSD use the same calculation for their IPv6 Addresses, this is
specified
in RFC4862 (IPv6 Stateless Address Autoconfiguration).

Under Linux it is mandatory that IPv6 Privacy Extensions are disabled:

$ sysctl -w net.ipv6.conf.all.use_tempaddr=0

Windows should be configured to use the MAC Address as the identifier for the EUI-64/SLAAC
calculation.

$ netsh interface ipv6 set privacy state=disabled store=persistent
$ netsh interface ipv6 set global randomizeidentifiers=disabled store=persistent

The IPv6 address is stored in the 'nics' table and is then returned by the API and will be
shown in the UI.

Searching for a conflicting IPv6 Address it NOT required as each IPv6 address is based on
the MAC Address
of the Instance and therefor unique.

Security Grouping has not been implemented yet and will follow in a upcoming commit.

Signed-off-by: Wido den Hollander <wido@widodh.nl>


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/c0e77667
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/c0e77667
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/c0e77667

Branch: refs/heads/master
Commit: c0e7766713b2631a167c2ceea7d42b574a5cd1b9
Parents: 9513053
Author: Wido den Hollander <wido@widodh.nl>
Authored: Wed Jul 20 12:10:53 2016 +0200
Committer: Wido den Hollander <wido@widodh.nl>
Committed: Thu Jan 26 15:17:33 2017 +0100

----------------------------------------------------------------------
 api/src/com/cloud/agent/api/to/NetworkTO.java   |  31 ++++++
 .../cloud/hypervisor/HypervisorGuruBase.java    |   2 +
 .../network/guru/DirectPodBasedNetworkGuru.java | 104 ++++++++++++-------
 .../main/java/com/cloud/utils/net/NetUtils.java |  19 ++++
 .../java/com/cloud/utils/net/NetUtilsTest.java  |  21 ++++
 5 files changed, 140 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c0e77667/api/src/com/cloud/agent/api/to/NetworkTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/NetworkTO.java b/api/src/com/cloud/agent/api/to/NetworkTO.java
index be11dea..9c88805 100644
--- a/api/src/com/cloud/agent/api/to/NetworkTO.java
+++ b/api/src/com/cloud/agent/api/to/NetworkTO.java
@@ -38,6 +38,8 @@ public class NetworkTO {
     protected URI isolationUri;
     protected boolean isSecurityGroupEnabled;
     protected String name;
+    protected String ip6address;
+    protected String ip6cidr;
 
     public NetworkTO() {
     }
@@ -62,6 +64,14 @@ public class NetworkTO {
         this.ip = ip;
     }
 
+    public void setIp6Address(String addr) {
+        this.ip6address = addr;
+    }
+
+    public void setIp6Cidr(String cidr) {
+        this.ip6cidr = cidr;
+    }
+
     public void setNetmask(String netmask) {
         this.netmask = netmask;
     }
@@ -114,6 +124,7 @@ public class NetworkTO {
      * the full information about what is needed.
      *
      * @param ip
+     * @param ip6address
      * @param vlan
      * @param netmask
      * @param mac
@@ -130,10 +141,30 @@ public class NetworkTO {
         this.dns2 = dns2;
     }
 
+    public NetworkTO(String ip, String netmask, String mac, String gateway, String dns1,
String dns2, String ip6address,
+                     String ip6cidr) {
+        this.ip = ip;
+        this.netmask = netmask;
+        this.mac = mac;
+        this.gateway = gateway;
+        this.dns1 = dns1;
+        this.dns2 = dns2;
+        this.ip6address = ip6address;
+        this.ip6cidr = ip6cidr;
+    }
+
     public String getIp() {
         return ip;
     }
 
+    public String getIp6Address() {
+        return ip6address;
+    }
+
+    public String getIp6Cidr() {
+        return ip6cidr;
+    }
+
     public String getNetmask() {
         return netmask;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c0e77667/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
index e48c1f5..c413edd 100644
--- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
+++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
@@ -87,6 +87,8 @@ public abstract class HypervisorGuruBase extends AdapterBase implements
Hypervis
         to.setNetworkRateMbps(profile.getNetworkRate());
         to.setName(profile.getName());
         to.setSecurityGroupEnabled(profile.isSecurityGroupEnabled());
+        to.setIp6Address(profile.getIPv6Address());
+        to.setIp6Cidr(profile.getIPv6Cidr());
 
         NetworkVO network = _networkDao.findById(profile.getNetworkId());
         to.setNetworkUuid(network.getUuid());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c0e77667/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java b/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
index 9154ece..6301ca5 100644
--- a/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
+++ b/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java
@@ -30,6 +30,7 @@ import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.Pod;
 import com.cloud.dc.PodVlanMapVO;
 import com.cloud.dc.Vlan;
+import com.cloud.dc.VlanVO;
 import com.cloud.dc.Vlan.VlanType;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.PodVlanMapDao;
@@ -54,12 +55,14 @@ import com.cloud.utils.db.TransactionCallbackNoReturn;
 import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
 import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.net.NetUtils;
 import com.cloud.vm.Nic;
 import com.cloud.vm.Nic.ReservationStrategy;
 import com.cloud.vm.NicProfile;
 import com.cloud.vm.ReservationContext;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineProfile;
+import com.googlecode.ipv6.IPv6Address;
 
 public class DirectPodBasedNetworkGuru extends DirectNetworkGuru {
     private static final Logger s_logger = Logger.getLogger(DirectPodBasedNetworkGuru.class);
@@ -166,54 +169,81 @@ public class DirectPodBasedNetworkGuru extends DirectNetworkGuru {
     protected void getIp(final NicProfile nic, final Pod pod, final VirtualMachineProfile
vm, final Network network) throws InsufficientVirtualNetworkCapacityException,
         InsufficientAddressCapacityException, ConcurrentOperationException {
         final DataCenter dc = _dcDao.findById(pod.getDataCenterId());
-        if (nic.getIPv4Address() == null) {
             Transaction.execute(new TransactionCallbackWithExceptionNoReturn<InsufficientAddressCapacityException>()
{
                 @Override
                 public void doInTransactionWithoutResult(TransactionStatus status) throws
InsufficientAddressCapacityException {
                     PublicIp ip = null;
                     List<PodVlanMapVO> podRefs = _podVlanDao.listPodVlanMapsByPod(pod.getId());
-                    String podRangeGateway = null;
-                    if (!podRefs.isEmpty()) {
-                        podRangeGateway = _vlanDao.findById(podRefs.get(0).getVlanDbId()).getVlanGateway();
-                    }
-                    //Get ip address from the placeholder and don't allocate a new one
-                    if (vm.getType() == VirtualMachine.Type.DomainRouter) {
-                        Nic placeholderNic = _networkModel.getPlaceholderNicForRouter(network,
pod.getId());
-                        if (placeholderNic != null) {
-                            IPAddressVO userIp = _ipAddressDao.findByIpAndSourceNetworkId(network.getId(),
placeholderNic.getIPv4Address());
-                            ip = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
-                            s_logger.debug("Nic got an ip address " + placeholderNic.getIPv4Address()
+ " stored in placeholder nic for the network " + network +
-                                " and gateway " + podRangeGateway);
+                    VlanVO vlan = _vlanDao.findById(podRefs.get(0).getVlanDbId());
+
+                    if (nic.getIPv4Address() == null) {
+                        String podRangeGateway = null;
+                        if (!podRefs.isEmpty()) {
+                            podRangeGateway = vlan.getVlanGateway();
+                        }
+                        //Get ip address from the placeholder and don't allocate a new one
+                        if (vm.getType() == VirtualMachine.Type.DomainRouter) {
+                            Nic placeholderNic = _networkModel.getPlaceholderNicForRouter(network,
pod.getId());
+                            if (placeholderNic != null) {
+                                IPAddressVO userIp = _ipAddressDao.findByIpAndSourceNetworkId(network.getId(),
placeholderNic.getIPv4Address());
+                                ip = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
+                                s_logger.debug("Nic got an ip address " + placeholderNic.getIPv4Address()
+ " stored in placeholder nic for the network " + network +
+                                    " and gateway " + podRangeGateway);
+                            }
                         }
-                    }
 
-                    if (ip == null) {
-                        ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(),
VlanType.DirectAttached, network.getId(), null, false);
-                    }
+                        if (ip == null) {
+                            ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), pod.getId(),
vm.getOwner(), VlanType.DirectAttached, network.getId(), null, false);
+                        }
 
-                    nic.setIPv4Address(ip.getAddress().toString());
-                    nic.setFormat(AddressFormat.Ip4);
-                    nic.setIPv4Gateway(ip.getGateway());
-                    nic.setIPv4Netmask(ip.getNetmask());
-                    if (ip.getVlanTag() != null && ip.getVlanTag().equalsIgnoreCase(Vlan.UNTAGGED))
{
-                        nic.setIsolationUri(IsolationType.Ec2.toUri(Vlan.UNTAGGED));
-                        nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(Vlan.UNTAGGED));
-                        nic.setBroadcastType(BroadcastDomainType.Native);
-                    }
-                    nic.setReservationId(String.valueOf(ip.getVlanTag()));
-                    nic.setMacAddress(ip.getMacAddress());
-
-                    //save the placeholder nic if the vm is the Virtual router
-                    if (vm.getType() == VirtualMachine.Type.DomainRouter) {
-                        Nic placeholderNic = _networkModel.getPlaceholderNicForRouter(network,
pod.getId());
-                        if (placeholderNic == null) {
-                            s_logger.debug("Saving placeholder nic with ip4 address " + nic.getIPv4Address()
+ " for the network " + network);
-                            _networkMgr.savePlaceholderNic(network, nic.getIPv4Address(),
null, VirtualMachine.Type.DomainRouter);
+                        nic.setIPv4Address(ip.getAddress().toString());
+                        nic.setFormat(AddressFormat.Ip4);
+                        nic.setIPv4Gateway(ip.getGateway());
+                        nic.setIPv4Netmask(ip.getNetmask());
+                        if (ip.getVlanTag() != null && ip.getVlanTag().equalsIgnoreCase(Vlan.UNTAGGED))
{
+                            nic.setIsolationUri(IsolationType.Ec2.toUri(Vlan.UNTAGGED));
+                            nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(Vlan.UNTAGGED));
+                            nic.setBroadcastType(BroadcastDomainType.Native);
                         }
+                        nic.setReservationId(String.valueOf(ip.getVlanTag()));
+                        nic.setMacAddress(ip.getMacAddress());
+
+                        //save the placeholder nic if the vm is the Virtual router
+                        if (vm.getType() == VirtualMachine.Type.DomainRouter) {
+                            Nic placeholderNic = _networkModel.getPlaceholderNicForRouter(network,
pod.getId());
+                            if (placeholderNic == null) {
+                                s_logger.debug("Saving placeholder nic with ip4 address "
+ nic.getIPv4Address() + " for the network " + network);
+                                _networkMgr.savePlaceholderNic(network, nic.getIPv4Address(),
null, VirtualMachine.Type.DomainRouter);
+                            }
+                        }
+                }
+
+                /**
+                 * Calculate the IPv6 Address the Instance will obtain using SLAAC and IPv6
EUI-64
+                 *
+                 * Linux, FreeBSD and Windows all calculate the same IPv6 address when configured
properly.
+                 *
+                 * Using Router Advertisements the routers in the network should announce
the IPv6 CIDR which is configured
+                 * in in the vlan table in the database.
+                 *
+                 * This way the NIC will be populated with a IPv6 address on which the Instance
is reachable.
+                 */
+                if (vlan.getIp6Cidr() != null) {
+                    if (nic.getIPv6Address() == null) {
+                        s_logger.debug("Found IPv6 CIDR " + vlan.getIp6Cidr() + " for VLAN
" + vlan.getId());
+                        nic.setIPv6Cidr(vlan.getIp6Cidr());
+                        nic.setIPv6Gateway(vlan.getIp6Gateway());
+
+                        IPv6Address ipv6addr = NetUtils.EUI64Address(vlan.getIp6Cidr(), nic.getMacAddress());
+                        s_logger.info("Calculated IPv6 address " + ipv6addr + " using EUI-64
for NIC " + nic.getUuid());
+                        nic.setIPv6Address(ipv6addr.toString());
                     }
+                } else {
+                    s_logger.debug("No IPv6 CIDR configured for VLAN " + vlan.getId());
                 }
-            });
-        }
+            }
+        });
+
         nic.setIPv4Dns1(dc.getDns1());
         nic.setIPv4Dns2(dc.getDns2());
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c0e77667/utils/src/main/java/com/cloud/utils/net/NetUtils.java
----------------------------------------------------------------------
diff --git a/utils/src/main/java/com/cloud/utils/net/NetUtils.java b/utils/src/main/java/com/cloud/utils/net/NetUtils.java
index a73813c..a2ec411 100644
--- a/utils/src/main/java/com/cloud/utils/net/NetUtils.java
+++ b/utils/src/main/java/com/cloud/utils/net/NetUtils.java
@@ -1578,5 +1578,24 @@ public class NetUtils {
         return !isInRange;
     }
 
+    public static IPv6Address EUI64Address(final IPv6Network cidr, final String macAddress)
{
+        if (cidr.getNetmask().asPrefixLength() > 64) {
+            throw new IllegalArgumentException("IPv6 subnet " + cidr.toString() + " is not
64 bits or larger in size");
+        }
+
+        String mac[] = macAddress.toLowerCase().split(":");
+
+        return IPv6Address.fromString(cidr.getFirst().toString() +
+                Integer.toHexString(Integer.parseInt(mac[0], 16) ^ 2) +
+                mac[1] + ":" + mac[2] + "ff:fe" + mac[3] +":" + mac[4] + mac[5]);
+    }
+
+    public static IPv6Address EUI64Address(final String cidr, final String macAddress) {
+        return EUI64Address(IPv6Network.fromString(cidr), macAddress);
+    }
+
+    public static IPv6Address ipv6LinkLocal(final String macAddress) {
+        return EUI64Address(IPv6Network.fromString("fe80::/64"), macAddress);
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c0e77667/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
----------------------------------------------------------------------
diff --git a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
index 490d0df..4c43751 100644
--- a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
+++ b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
@@ -526,4 +526,25 @@ public class NetUtilsTest {
         assertFalse(NetUtils.isNetworkorBroadcastIP("192.168.0.63","255.255.255.128"));
     }
 
+    @Test
+    public void testIPv6EUI64Address() {
+        assertEquals(IPv6Address.fromString("2001:db8:100::47a:88ff:fe00:8b"),
+                NetUtils.EUI64Address("2001:db8:100::/64", "06:7a:88:00:00:8b"));
+
+        assertEquals(IPv6Address.fromString("2a00:f10:121:b00:434:a0ff:fe00:1bc7"),
+                NetUtils.EUI64Address("2a00:f10:121:b00::/64", "06:34:a0:00:1b:c7"));
+
+        assertEquals(IPv6Address.fromString("2001:980:7936:0:ea2a:eaff:fe58:eb98"),
+                NetUtils.EUI64Address("2001:980:7936::/64", "e8:2a:ea:58:eb:98"));
+
+        assertEquals(IPv6Address.fromString("2001:980:7936:0:c23f:d5ff:fe68:2808"),
+                NetUtils.EUI64Address("2001:980:7936::/64", "c0:3f:d5:68:28:08"));
+    }
+
+    @Test
+    public void testIPv6LinkLocal() {
+        assertEquals(IPv6Address.fromString("fe80::fc54:ff:fe00:3e05"), NetUtils.ipv6LinkLocal("fe:54:00:00:3e:05"));
+        assertEquals(IPv6Address.fromString("fe80::42:e0ff:fee8:d6a3"), NetUtils.ipv6LinkLocal("02:42:e0:e8:d6:a3"));
+        assertEquals(IPv6Address.fromString("fe80::47a:88ff:fe00:8b"), NetUtils.ipv6LinkLocal("06:7a:88:00:00:8b"));
+    }
 }


Mime
View raw message