blob: 7d20b6507699d7296ffa67765c1334242758c91d [file] [log] [blame]
Jian Libde20bf2019-01-25 17:34:43 +09001/*
2 * Copyright 2019-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.k8snetworking.util;
17
18import com.fasterxml.jackson.core.JsonParseException;
19import com.fasterxml.jackson.core.JsonProcessingException;
20import com.fasterxml.jackson.databind.JsonMappingException;
21import com.fasterxml.jackson.databind.ObjectMapper;
Jian Li2cc2b632019-02-18 00:56:40 +090022import com.google.common.collect.Maps;
Jian Lie1a5b8f2019-07-23 17:13:19 +090023import io.fabric8.kubernetes.api.model.Container;
24import io.fabric8.kubernetes.api.model.ContainerPort;
25import io.fabric8.kubernetes.api.model.Namespace;
26import io.fabric8.kubernetes.api.model.Pod;
Jian Li85387732019-02-19 23:56:18 +090027import io.fabric8.kubernetes.client.ConfigBuilder;
28import io.fabric8.kubernetes.client.DefaultKubernetesClient;
29import io.fabric8.kubernetes.client.KubernetesClient;
30import org.apache.commons.lang3.StringUtils;
Jian Li9b199162019-02-10 18:00:35 +090031import org.apache.commons.net.util.SubnetUtils;
32import org.onlab.packet.IpAddress;
Jian Li4bd6f2b2019-08-16 21:39:27 +090033import org.onlab.packet.MacAddress;
Jian Li140d8a22019-04-24 23:41:44 +090034import org.onlab.packet.TpPort;
Jian Li4aa17642019-01-30 00:01:11 +090035import org.onosproject.cfg.ConfigProperty;
Jian Li4bd6f2b2019-08-16 21:39:27 +090036import org.onosproject.k8snetworking.api.DefaultK8sPort;
Jian Lie1a5b8f2019-07-23 17:13:19 +090037import org.onosproject.k8snetworking.api.K8sNamespaceService;
Jian Li4aa17642019-01-30 00:01:11 +090038import org.onosproject.k8snetworking.api.K8sNetwork;
Jian Li4bd6f2b2019-08-16 21:39:27 +090039import org.onosproject.k8snetworking.api.K8sNetworkAdminService;
Jian Li4aa17642019-01-30 00:01:11 +090040import org.onosproject.k8snetworking.api.K8sNetworkService;
Jian Lie1a5b8f2019-07-23 17:13:19 +090041import org.onosproject.k8snetworking.api.K8sPodService;
Jian Li4bd6f2b2019-08-16 21:39:27 +090042import org.onosproject.k8snetworking.api.K8sPort;
Jian Lie1a5b8f2019-07-23 17:13:19 +090043import org.onosproject.k8snetworking.api.K8sServiceService;
Jian Li85387732019-02-19 23:56:18 +090044import org.onosproject.k8snode.api.K8sApiConfig;
Jian Li3d1111e2019-02-22 02:02:13 +090045import org.onosproject.k8snode.api.K8sApiConfigService;
Jian Li4aa17642019-01-30 00:01:11 +090046import org.onosproject.k8snode.api.K8sNode;
Jian Li2cc2b632019-02-18 00:56:40 +090047import org.onosproject.k8snode.api.K8sNodeService;
Jian Li4bd6f2b2019-08-16 21:39:27 +090048import org.onosproject.net.DeviceId;
Jian Li4aa17642019-01-30 00:01:11 +090049import org.onosproject.net.PortNumber;
Jian Li2cc2b632019-02-18 00:56:40 +090050import org.onosproject.net.group.DefaultGroupKey;
51import org.onosproject.net.group.GroupKey;
Jian Libde20bf2019-01-25 17:34:43 +090052import org.slf4j.Logger;
53import org.slf4j.LoggerFactory;
54
55import java.io.IOException;
Jian Li9b199162019-02-10 18:00:35 +090056import java.util.Arrays;
57import java.util.HashSet;
Jian Li2cc2b632019-02-18 00:56:40 +090058import java.util.Map;
Jian Li140d8a22019-04-24 23:41:44 +090059import java.util.Objects;
Jian Li4aa17642019-01-30 00:01:11 +090060import java.util.Optional;
61import java.util.Set;
Jian Li9b199162019-02-10 18:00:35 +090062import java.util.stream.Collectors;
Jian Libde20bf2019-01-25 17:34:43 +090063
Jian Lie1a5b8f2019-07-23 17:13:19 +090064import static org.onosproject.k8snetworking.api.Constants.DEFAULT_NAMESPACE_HASH;
Jian Libde20bf2019-01-25 17:34:43 +090065import static org.onosproject.k8snetworking.api.Constants.PORT_NAME_PREFIX_CONTAINER;
Jian Li4bd6f2b2019-08-16 21:39:27 +090066import static org.onosproject.k8snetworking.api.K8sPort.State.INACTIVE;
Jian Libde20bf2019-01-25 17:34:43 +090067
68/**
69 * An utility that used in kubernetes networking app.
70 */
71public final class K8sNetworkingUtil {
72
73 private static final Logger log = LoggerFactory.getLogger(K8sNetworkingUtil.class);
74
Jian Li85387732019-02-19 23:56:18 +090075 private static final String COLON_SLASH = "://";
76 private static final String COLON = ":";
77
Jian Li140d8a22019-04-24 23:41:44 +090078 private static final String STR_ZERO = "0";
79 private static final String STR_ONE = "1";
80 private static final String STR_PADDING = "0000000000000000";
81 private static final int MASK_BEGIN_IDX = 0;
82 private static final int MASK_MAX_IDX = 16;
83 private static final int MASK_RADIX = 2;
84 private static final int PORT_RADIX = 16;
85
Jian Li4bd6f2b2019-08-16 21:39:27 +090086 private static final String PORT_ID = "portId";
87 private static final String DEVICE_ID = "deviceId";
88 private static final String PORT_NUMBER = "portNumber";
89 private static final String IP_ADDRESS = "ipAddress";
90 private static final String MAC_ADDRESS = "macAddress";
91 private static final String NETWORK_ID = "networkId";
92
Jian Libde20bf2019-01-25 17:34:43 +090093 private K8sNetworkingUtil() {
94 }
95
96 /**
97 * Checks that whether the port is associated with container interface.
98 *
99 * @param portName port name
100 * @return true if the port is associated with container; false otherwise
101 */
102 public static boolean isContainer(String portName) {
Jian Li4aa17642019-01-30 00:01:11 +0900103 return portName != null && portName.contains(PORT_NAME_PREFIX_CONTAINER);
104 }
105
106 /**
107 * Returns the tunnel port number with specified net ID and kubernetes node.
108 *
109 * @param netId network ID
110 * @param netService network service
111 * @param node kubernetes node
112 * @return tunnel port number
113 */
114 public static PortNumber tunnelPortNumByNetId(String netId,
115 K8sNetworkService netService,
116 K8sNode node) {
117 K8sNetwork.Type netType = netService.network(netId).type();
118
119 if (netType == null) {
120 return null;
121 }
122
123 return tunnelPortNumByNetType(netType, node);
124 }
125
126 /**
127 * Returns the tunnel port number with specified net type and kubernetes node.
128 *
129 * @param netType network type
130 * @param node kubernetes node
131 * @return tunnel port number
132 */
133 public static PortNumber tunnelPortNumByNetType(K8sNetwork.Type netType,
134 K8sNode node) {
135 switch (netType) {
136 case VXLAN:
137 return node.vxlanPortNum();
138 case GRE:
139 return node.grePortNum();
140 case GENEVE:
141 return node.genevePortNum();
142 default:
143 return null;
144 }
145 }
146
147 /**
148 * Obtains the property value with specified property key name.
149 *
150 * @param properties a collection of properties
151 * @param name key name
152 * @return mapping value
153 */
154 public static String getPropertyValue(Set<ConfigProperty> properties,
155 String name) {
156 Optional<ConfigProperty> property =
157 properties.stream().filter(p -> p.name().equals(name)).findFirst();
158 return property.map(ConfigProperty::value).orElse(null);
Jian Libde20bf2019-01-25 17:34:43 +0900159 }
160
161 /**
162 * Prints out the JSON string in pretty format.
163 *
164 * @param mapper Object mapper
165 * @param jsonString JSON string
166 * @return pretty formatted JSON string
167 */
168 public static String prettyJson(ObjectMapper mapper, String jsonString) {
169 try {
170 Object jsonObject = mapper.readValue(jsonString, Object.class);
171 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
172 } catch (JsonParseException e) {
Jian Li003d5692019-08-26 23:19:38 +0900173 log.debug("JsonParseException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900174 } catch (JsonMappingException e) {
Jian Li003d5692019-08-26 23:19:38 +0900175 log.debug("JsonMappingException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900176 } catch (JsonProcessingException e) {
Jian Li003d5692019-08-26 23:19:38 +0900177 log.debug("JsonProcessingException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900178 } catch (IOException e) {
Jian Li003d5692019-08-26 23:19:38 +0900179 log.debug("IOException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900180 }
181 return null;
182 }
Jian Li9b199162019-02-10 18:00:35 +0900183
184 /**
185 * Obtains valid IP addresses of the given subnet.
186 *
187 * @param cidr CIDR
188 * @return set of IP addresses
189 */
190 public static Set<IpAddress> getSubnetIps(String cidr) {
191 SubnetUtils utils = new SubnetUtils(cidr);
Jian Li7970b712019-05-03 20:58:21 +0900192 utils.setInclusiveHostCount(false);
Jian Li9b199162019-02-10 18:00:35 +0900193 SubnetUtils.SubnetInfo info = utils.getInfo();
194 Set<String> allAddresses =
195 new HashSet<>(Arrays.asList(info.getAllAddresses()));
196
197 if (allAddresses.size() > 2) {
Jian Li7970b712019-05-03 20:58:21 +0900198 allAddresses.remove(info.getLowAddress());
199 allAddresses.remove(info.getHighAddress());
Jian Li9b199162019-02-10 18:00:35 +0900200 }
201
202 return allAddresses.stream()
203 .map(IpAddress::valueOf).collect(Collectors.toSet());
204 }
Jian Li85387732019-02-19 23:56:18 +0900205
206 /**
Jian Li2cc2b632019-02-18 00:56:40 +0900207 * Obtains flow group key from the given id.
208 *
209 * @param groupId flow group identifier
210 * @return flow group key
211 */
212 public static GroupKey getGroupKey(int groupId) {
213 return new DefaultGroupKey((Integer.toString(groupId)).getBytes());
214 }
215
216 /**
Jian Li85387732019-02-19 23:56:18 +0900217 * Generates endpoint URL by referring to scheme, ipAddress and port.
218 *
219 * @param scheme scheme
220 * @param ipAddress IP address
221 * @param port port number
222 * @return generated endpoint URL
223 */
224 public static String endpoint(K8sApiConfig.Scheme scheme, IpAddress ipAddress, int port) {
225 StringBuilder endpoint = new StringBuilder();
226 String protocol = StringUtils.lowerCase(scheme.name());
227
228 endpoint.append(protocol);
229 endpoint.append(COLON_SLASH);
230 endpoint.append(ipAddress.toString());
231 endpoint.append(COLON);
232 endpoint.append(port);
233
234 return endpoint.toString();
235 }
236
237 /**
238 * Generates endpoint URL by referring to scheme, ipAddress and port.
239 *
240 * @param apiConfig kubernetes API config
241 * @return generated endpoint URL
242 */
243 public static String endpoint(K8sApiConfig apiConfig) {
244 return endpoint(apiConfig.scheme(), apiConfig.ipAddress(), apiConfig.port());
245 }
246
247 /**
248 * Obtains workable kubernetes client.
249 *
250 * @param config kubernetes API config
251 * @return kubernetes client
252 */
253 public static KubernetesClient k8sClient(K8sApiConfig config) {
254 if (config == null) {
255 log.warn("Kubernetes API server config is empty.");
256 return null;
257 }
258
259 String endpoint = endpoint(config);
260
261 ConfigBuilder configBuilder = new ConfigBuilder().withMasterUrl(endpoint);
262
263 if (config.scheme() == K8sApiConfig.Scheme.HTTPS) {
264 configBuilder.withTrustCerts(true)
265 .withOauthToken(config.token())
266 .withCaCertData(config.caCertData())
267 .withClientCertData(config.clientCertData())
268 .withClientKeyData(config.clientKeyData());
269 }
270
271 return new DefaultKubernetesClient(configBuilder.build());
272 }
Jian Li3d1111e2019-02-22 02:02:13 +0900273
274 /**
275 * Obtains workable kubernetes client.
276 *
277 * @param service kubernetes API service
278 * @return kubernetes client
279 */
280 public static KubernetesClient k8sClient(K8sApiConfigService service) {
281 K8sApiConfig config =
282 service.apiConfigs().stream().findAny().orElse(null);
283 if (config == null) {
284 log.error("Failed to find valid kubernetes API configuration.");
285 return null;
286 }
287
288 KubernetesClient client = k8sClient(config);
289
290 if (client == null) {
291 log.error("Failed to connect to kubernetes API server.");
292 return null;
293 }
294
295 return client;
296 }
Jian Li2cc2b632019-02-18 00:56:40 +0900297
298 /**
299 * Obtains the kubernetes node IP and kubernetes network gateway IP map.
300 *
301 * @param nodeService kubernetes node service
302 * @param networkService kubernetes network service
303 * @return kubernetes node IP and kubernetes network gateway IP map
304 */
305 public static Map<String, String> nodeIpGatewayIpMap(K8sNodeService nodeService,
306 K8sNetworkService networkService) {
307 Map<String, String> ipMap = Maps.newConcurrentMap();
308
309 nodeService.completeNodes().forEach(n -> {
310 K8sNetwork network = networkService.network(n.hostname());
311 if (network != null) {
312 ipMap.put(n.dataIp().toString(), network.gatewayIp().toString());
313 }
314 });
315
316 return ipMap;
317 }
Jian Li004526d2019-02-25 16:26:27 +0900318
319 /**
Jian Li73d3b6a2019-07-08 18:07:53 +0900320 * Returns a shifted IP address.
321 *
322 * @param ipAddress IP address to be shifted
323 * @param shiftPrefix A IP prefix used in shifted IP address
324 * @return shifted Ip address
325 */
326 public static String shiftIpDomain(String ipAddress, String shiftPrefix) {
327 String origIpPrefix = ipAddress.split("\\.")[0] + "." + ipAddress.split("\\.")[1];
328 return StringUtils.replace(ipAddress, origIpPrefix, shiftPrefix);
329 }
330
331 /**
Jian Li140d8a22019-04-24 23:41:44 +0900332 * Returns an unshifted IP address.
Jian Li004526d2019-02-25 16:26:27 +0900333 *
Jian Li140d8a22019-04-24 23:41:44 +0900334 * @param ipAddress IP address to be unshifted
335 * @param ipPrefix IP prefix which to be used for unshifting
336 * @param cidr a POD network CIDR
337 * @return unshifted IP address
Jian Li004526d2019-02-25 16:26:27 +0900338 */
Jian Li140d8a22019-04-24 23:41:44 +0900339 public static String unshiftIpDomain(String ipAddress,
340 String ipPrefix,
341 String cidr) {
Jian Li004526d2019-02-25 16:26:27 +0900342
Jian Li140d8a22019-04-24 23:41:44 +0900343 String origIpPrefix = cidr.split("\\.")[0] + "." + cidr.split("\\.")[1];
344 return StringUtils.replace(ipAddress, ipPrefix, origIpPrefix);
345 }
Jian Li004526d2019-02-25 16:26:27 +0900346
Jian Li140d8a22019-04-24 23:41:44 +0900347 /**
348 * Returns the B class IP prefix of the given CIDR.
349 *
350 * @param cidr CIDR
351 * @return IP prefix
352 */
353 public static String getBclassIpPrefixFromCidr(String cidr) {
354 if (cidr == null) {
355 return null;
356 }
357 return cidr.split("\\.")[0] + "." + cidr.split("\\.")[1];
358 }
Jian Li004526d2019-02-25 16:26:27 +0900359
Jian Li140d8a22019-04-24 23:41:44 +0900360 /**
361 * Returns the A class IP prefix of the given CIDR.
362 *
363 * @param cidr CIDR
364 * @return IP prefix
365 */
366 public static String getAclassIpPrefixFromCidr(String cidr) {
367 if (cidr == null) {
368 return null;
369 }
370 return cidr.split("\\.")[0];
371 }
372
373 /**
374 * Returns the map of port range.
375 *
376 * @param portMin minimum port number
377 * @param portMax maximum port number
378 * @return map of port range
379 */
380 public static Map<TpPort, TpPort> buildPortRangeMatches(int portMin, int portMax) {
381
382 boolean processing = true;
383 int start = portMin;
384 Map<TpPort, TpPort> portMaskMap = Maps.newHashMap();
385 while (processing) {
386 String minStr = Integer.toBinaryString(start);
387 String binStrMinPadded = STR_PADDING.substring(minStr.length()) + minStr;
388
389 int mask = testMasks(binStrMinPadded, start, portMax);
390 int maskStart = binLower(binStrMinPadded, mask);
391 int maskEnd = binHigher(binStrMinPadded, mask);
392
393 log.debug("start : {} port/mask = {} / {} ", start, getMask(mask), maskStart);
394 portMaskMap.put(TpPort.tpPort(maskStart), TpPort.tpPort(
395 Integer.parseInt(Objects.requireNonNull(getMask(mask)), PORT_RADIX)));
396
397 start = maskEnd + 1;
398 if (start > portMax) {
399 processing = false;
400 }
401 }
402
403 return portMaskMap;
404 }
405
Jian Lie1a5b8f2019-07-23 17:13:19 +0900406 /**
407 * Returns the namespace hash value by given POD IP.
408 *
409 * @param k8sPodService kubernetes POD service
410 * @param k8sNamespaceService kubernetes namespace service
411 * @param podIp POD IP address
412 * @return namespace hash value
413 */
414 public static Integer namespaceHashByPodIp(K8sPodService k8sPodService,
415 K8sNamespaceService k8sNamespaceService,
416 String podIp) {
417 String ns = k8sPodService.pods().stream()
418 .filter(pod -> pod.getStatus().getPodIP() != null)
419 .filter(pod -> pod.getStatus().getPodIP().equals(podIp))
420 .map(pod -> pod.getMetadata().getNamespace())
421 .findAny().orElse(null);
422
423 if (ns != null) {
424 return k8sNamespaceService.namespaces().stream()
425 .filter(n -> n.getMetadata().getName().equals(ns))
426 .map(Namespace::hashCode).findAny().orElse(null);
427 } else {
428 return null;
429 }
430 }
431
432 /**
433 * Returns the namespace hash value by given service IP.
434 *
435 * @param k8sServiceService kubernetes service service
436 * @param k8sNamespaceService kubernetes namespace service
437 * @param serviceIp service IP address
438 * @return namespace hash value
439 */
440 public static int namespaceHashByServiceIp(K8sServiceService k8sServiceService,
441 K8sNamespaceService k8sNamespaceService,
442 String serviceIp) {
443 String ns = k8sServiceService.services().stream()
444 .filter(service -> service.getSpec().getClusterIP() != null)
445 .filter(service -> service.getSpec().getClusterIP().equalsIgnoreCase(serviceIp))
446 .map(service -> service.getMetadata().getNamespace())
447 .findAny().orElse(null);
448
449 if (ns != null) {
450 return namespaceHashByNamespace(k8sNamespaceService, ns);
451 } else {
452 return DEFAULT_NAMESPACE_HASH;
453 }
454 }
455
456 /**
457 * Returns the namespace hash value by given namespace name.
458 *
459 * @param k8sNamespaceService kubernetes namespace service
460 * @param ns namespace name
461 * @return namespace hash value
462 */
463 public static int namespaceHashByNamespace(K8sNamespaceService k8sNamespaceService,
464 String ns) {
465
466 return k8sNamespaceService.namespaces().stream()
467 .filter(n -> n.getMetadata().getName() != null)
468 .filter(n -> n.getMetadata().getName().equalsIgnoreCase(ns))
469 .map(Namespace::hashCode).findAny().orElse(DEFAULT_NAMESPACE_HASH);
470 }
471
472 /**
473 * Returns POD instance by POD IP address.
474 *
475 * @param podService kubernetes POD service
476 * @param podIp POD IP address
477 * @return POD instance
478 */
479 public static Pod podByIp(K8sPodService podService, String podIp) {
480 return podService.pods().stream()
481 .filter(pod -> pod.getStatus().getPodIP() != null)
482 .filter(pod -> pod.getStatus().getPodIP().equals(podIp))
483 .findAny().orElse(null);
484 }
485
486 /**
487 * Returns the container port number by given container port name.
488 *
489 * @param pod kubernetes POD
490 * @param portName port name
491 * @return container port number,
492 * return 0 if there is no port number mapped with the given port name
493 */
494 public static int portNumberByName(Pod pod, String portName) {
Jian Li5cf3b002019-08-30 17:57:53 +0900495
496 if (pod == null || pod.getSpec() == null) {
497 return 0;
498 }
499
Jian Lie1a5b8f2019-07-23 17:13:19 +0900500 for (Container container : pod.getSpec().getContainers()) {
501 for (ContainerPort cp : container.getPorts()) {
502 if (cp.getName() != null && cp.getName().equals(portName)) {
503 return cp.getContainerPort();
504 }
505 }
506 }
507
508 return 0;
509 }
510
Jian Li4bd6f2b2019-08-16 21:39:27 +0900511 /**
512 * Synchronizes port from kubernetes POD.
513 *
514 * @param pod kubernetes POD
515 * @param adminService admin service
516 */
517 public static void syncPortFromPod(Pod pod, K8sNetworkAdminService adminService) {
518 Map<String, String> annotations = pod.getMetadata().getAnnotations();
519 if (annotations != null && !annotations.isEmpty() &&
520 annotations.get(PORT_ID) != null) {
521 String portId = annotations.get(PORT_ID);
522
523 K8sPort oldPort = adminService.port(portId);
524
525 String networkId = annotations.get(NETWORK_ID);
526 DeviceId deviceId = DeviceId.deviceId(annotations.get(DEVICE_ID));
527 PortNumber portNumber = PortNumber.portNumber(annotations.get(PORT_NUMBER));
528 IpAddress ipAddress = IpAddress.valueOf(annotations.get(IP_ADDRESS));
529 MacAddress macAddress = MacAddress.valueOf(annotations.get(MAC_ADDRESS));
530
531 K8sPort newPort = DefaultK8sPort.builder()
532 .portId(portId)
533 .networkId(networkId)
534 .deviceId(deviceId)
535 .ipAddress(ipAddress)
536 .macAddress(macAddress)
537 .portNumber(portNumber)
538 .state(INACTIVE)
539 .build();
540
541 if (oldPort == null) {
542 adminService.createPort(newPort);
543 } else {
544 adminService.updatePort(newPort);
545 }
546 }
547 }
548
Jian Li140d8a22019-04-24 23:41:44 +0900549 private static int binLower(String binStr, int bits) {
550 StringBuilder outBin = new StringBuilder(
551 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
552 for (int i = 0; i < bits; i++) {
553 outBin.append(STR_ZERO);
554 }
555
556 return Integer.parseInt(outBin.toString(), MASK_RADIX);
557 }
558
559 private static int binHigher(String binStr, int bits) {
560 StringBuilder outBin = new StringBuilder(
561 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
562 for (int i = 0; i < bits; i++) {
563 outBin.append(STR_ONE);
564 }
565
566 return Integer.parseInt(outBin.toString(), MASK_RADIX);
567 }
568
569 private static int testMasks(String binStr, int start, int end) {
570 int mask = MASK_BEGIN_IDX;
571 for (; mask <= MASK_MAX_IDX; mask++) {
572 int maskStart = binLower(binStr, mask);
573 int maskEnd = binHigher(binStr, mask);
574 if (maskStart < start || maskEnd > end) {
575 return mask - 1;
576 }
577 }
578
579 return mask;
580 }
581
582 private static String getMask(int bits) {
583 switch (bits) {
584 case 0: return "ffff";
585 case 1: return "fffe";
586 case 2: return "fffc";
587 case 3: return "fff8";
588 case 4: return "fff0";
589 case 5: return "ffe0";
590 case 6: return "ffc0";
591 case 7: return "ff80";
592 case 8: return "ff00";
593 case 9: return "fe00";
594 case 10: return "fc00";
595 case 11: return "f800";
596 case 12: return "f000";
597 case 13: return "e000";
598 case 14: return "c000";
599 case 15: return "8000";
600 case 16: return "0000";
601 default: return null;
602 }
Jian Li004526d2019-02-25 16:26:27 +0900603 }
Jian Libde20bf2019-01-25 17:34:43 +0900604}