/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.net; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Class that maps IPv6 addresses to Rack IDs. * Uses first 64 bits. * */ public class IPv6AddressTruncationMapping extends CachedDNSToSwitchMapping { private static final Log LOG = LogFactory.getLog(IPv6AddressTruncationMapping.class); private static final IPv4AddressTruncationMapping ipv4Mapper = new IPv4AddressTruncationMapping(); public IPv6AddressTruncationMapping() { super(new IPv6Truncator()); } private static class IPv6Truncator implements DNSToSwitchMapping { @Override public List<String> resolve(List<String> namesToResolve) { List<String> resolvedNames = new ArrayList<String>(namesToResolve.size()); for (int i = 0; i < namesToResolve.size(); i++) { String toResolve = namesToResolve.get(i); try { String rackId = getTruncatedAddress(toResolve); if (rackId == null) { rackId = NetworkTopology.DEFAULT_RACK; } resolvedNames.add(rackId); if (LOG.isInfoEnabled()) { LOG.info("Rack id for : " + toResolve + " is : " + resolvedNames.get(i)); } } catch (UnknownHostException uhe) { LOG.warn("Host unresolvable: " + toResolve); resolvedNames.add(NetworkTopology.DEFAULT_RACK); } } return resolvedNames; } private String getTruncatedAddress(String string) throws UnknownHostException { InetAddress ipAddress = InetAddress.getByName(string); if (ipAddress instanceof Inet4Address) { if (LOG.isErrorEnabled()) { LOG.error(IPv6AddressTruncationMapping.class.getName() + " is being used when the stack is working on IPv4 addresses.\n" + "Check flags: -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses"); } return ipv4Mapper.resolve(Arrays.asList(string)).get(0); } else if (ipAddress instanceof Inet6Address) { String rackId = ""; byte[] rawAddress = ipAddress.getAddress(); // for IPv6 addresses, we are using /64 as a rack identifier. // First 64 bits = First 8 bytes = 16 hex digits = 4 hex chunks final int hexChunksToConcatenate = 4; for (int i = 0; i < hexChunksToConcatenate; i++) { rackId += getTwoHexDigits(rawAddress[i * 2]) + getTwoHexDigits(rawAddress[i * 2 + 1]) + ":"; } return IPv4AddressTruncationMapping.RACK_HEADER + rackId + ":"; } return null; } } static String getTwoHexDigits(byte b) { return Integer.toHexString(((b >> 4) & 0xf)) + Integer.toHexString(b & 0xf); } }