blob: 17240fbceae522abfb2e7c026599a492a5b1a26f [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 Lia6f58382019-12-16 14:22:13 +090058import java.util.List;
Jian Li2cc2b632019-02-18 00:56:40 +090059import java.util.Map;
Jian Li140d8a22019-04-24 23:41:44 +090060import java.util.Objects;
Jian Li4aa17642019-01-30 00:01:11 +090061import java.util.Optional;
62import java.util.Set;
Jian Li9b199162019-02-10 18:00:35 +090063import java.util.stream.Collectors;
Jian Libde20bf2019-01-25 17:34:43 +090064
Jian Lie1a5b8f2019-07-23 17:13:19 +090065import static org.onosproject.k8snetworking.api.Constants.DEFAULT_NAMESPACE_HASH;
Jian Libde20bf2019-01-25 17:34:43 +090066import static org.onosproject.k8snetworking.api.Constants.PORT_NAME_PREFIX_CONTAINER;
Jian Li4bd6f2b2019-08-16 21:39:27 +090067import static org.onosproject.k8snetworking.api.K8sPort.State.INACTIVE;
Jian Libde20bf2019-01-25 17:34:43 +090068
69/**
70 * An utility that used in kubernetes networking app.
71 */
72public final class K8sNetworkingUtil {
73
74 private static final Logger log = LoggerFactory.getLogger(K8sNetworkingUtil.class);
75
Jian Li85387732019-02-19 23:56:18 +090076 private static final String COLON_SLASH = "://";
77 private static final String COLON = ":";
78
Jian Li140d8a22019-04-24 23:41:44 +090079 private static final String STR_ZERO = "0";
80 private static final String STR_ONE = "1";
81 private static final String STR_PADDING = "0000000000000000";
82 private static final int MASK_BEGIN_IDX = 0;
83 private static final int MASK_MAX_IDX = 16;
84 private static final int MASK_RADIX = 2;
85 private static final int PORT_RADIX = 16;
86
Jian Li4bd6f2b2019-08-16 21:39:27 +090087 private static final String PORT_ID = "portId";
88 private static final String DEVICE_ID = "deviceId";
89 private static final String PORT_NUMBER = "portNumber";
90 private static final String IP_ADDRESS = "ipAddress";
91 private static final String MAC_ADDRESS = "macAddress";
92 private static final String NETWORK_ID = "networkId";
93
Jian Libde20bf2019-01-25 17:34:43 +090094 private K8sNetworkingUtil() {
95 }
96
97 /**
98 * Checks that whether the port is associated with container interface.
99 *
100 * @param portName port name
101 * @return true if the port is associated with container; false otherwise
102 */
103 public static boolean isContainer(String portName) {
Jian Li4aa17642019-01-30 00:01:11 +0900104 return portName != null && portName.contains(PORT_NAME_PREFIX_CONTAINER);
105 }
106
107 /**
108 * Returns the tunnel port number with specified net ID and kubernetes node.
109 *
110 * @param netId network ID
111 * @param netService network service
112 * @param node kubernetes node
113 * @return tunnel port number
114 */
115 public static PortNumber tunnelPortNumByNetId(String netId,
116 K8sNetworkService netService,
117 K8sNode node) {
118 K8sNetwork.Type netType = netService.network(netId).type();
119
120 if (netType == null) {
121 return null;
122 }
123
124 return tunnelPortNumByNetType(netType, node);
125 }
126
127 /**
128 * Returns the tunnel port number with specified net type and kubernetes node.
129 *
130 * @param netType network type
131 * @param node kubernetes node
132 * @return tunnel port number
133 */
134 public static PortNumber tunnelPortNumByNetType(K8sNetwork.Type netType,
135 K8sNode node) {
136 switch (netType) {
137 case VXLAN:
138 return node.vxlanPortNum();
139 case GRE:
140 return node.grePortNum();
141 case GENEVE:
142 return node.genevePortNum();
143 default:
144 return null;
145 }
146 }
147
148 /**
149 * Obtains the property value with specified property key name.
150 *
151 * @param properties a collection of properties
152 * @param name key name
153 * @return mapping value
154 */
155 public static String getPropertyValue(Set<ConfigProperty> properties,
156 String name) {
157 Optional<ConfigProperty> property =
158 properties.stream().filter(p -> p.name().equals(name)).findFirst();
159 return property.map(ConfigProperty::value).orElse(null);
Jian Libde20bf2019-01-25 17:34:43 +0900160 }
161
162 /**
163 * Prints out the JSON string in pretty format.
164 *
165 * @param mapper Object mapper
166 * @param jsonString JSON string
167 * @return pretty formatted JSON string
168 */
169 public static String prettyJson(ObjectMapper mapper, String jsonString) {
170 try {
171 Object jsonObject = mapper.readValue(jsonString, Object.class);
172 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
173 } catch (JsonParseException e) {
Jian Li003d5692019-08-26 23:19:38 +0900174 log.debug("JsonParseException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900175 } catch (JsonMappingException e) {
Jian Li003d5692019-08-26 23:19:38 +0900176 log.debug("JsonMappingException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900177 } catch (JsonProcessingException e) {
Jian Li003d5692019-08-26 23:19:38 +0900178 log.debug("JsonProcessingException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900179 } catch (IOException e) {
Jian Li003d5692019-08-26 23:19:38 +0900180 log.debug("IOException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900181 }
182 return null;
183 }
Jian Li9b199162019-02-10 18:00:35 +0900184
185 /**
186 * Obtains valid IP addresses of the given subnet.
187 *
188 * @param cidr CIDR
189 * @return set of IP addresses
190 */
191 public static Set<IpAddress> getSubnetIps(String cidr) {
192 SubnetUtils utils = new SubnetUtils(cidr);
Jian Li7970b712019-05-03 20:58:21 +0900193 utils.setInclusiveHostCount(false);
Jian Li9b199162019-02-10 18:00:35 +0900194 SubnetUtils.SubnetInfo info = utils.getInfo();
195 Set<String> allAddresses =
196 new HashSet<>(Arrays.asList(info.getAllAddresses()));
197
198 if (allAddresses.size() > 2) {
Jian Li7970b712019-05-03 20:58:21 +0900199 allAddresses.remove(info.getLowAddress());
200 allAddresses.remove(info.getHighAddress());
Jian Li9b199162019-02-10 18:00:35 +0900201 }
202
203 return allAddresses.stream()
204 .map(IpAddress::valueOf).collect(Collectors.toSet());
205 }
Jian Li85387732019-02-19 23:56:18 +0900206
207 /**
Jian Li2cc2b632019-02-18 00:56:40 +0900208 * Obtains flow group key from the given id.
209 *
210 * @param groupId flow group identifier
211 * @return flow group key
212 */
213 public static GroupKey getGroupKey(int groupId) {
214 return new DefaultGroupKey((Integer.toString(groupId)).getBytes());
215 }
216
217 /**
Jian Li85387732019-02-19 23:56:18 +0900218 * Generates endpoint URL by referring to scheme, ipAddress and port.
219 *
220 * @param scheme scheme
221 * @param ipAddress IP address
222 * @param port port number
223 * @return generated endpoint URL
224 */
225 public static String endpoint(K8sApiConfig.Scheme scheme, IpAddress ipAddress, int port) {
226 StringBuilder endpoint = new StringBuilder();
227 String protocol = StringUtils.lowerCase(scheme.name());
228
229 endpoint.append(protocol);
230 endpoint.append(COLON_SLASH);
231 endpoint.append(ipAddress.toString());
232 endpoint.append(COLON);
233 endpoint.append(port);
234
235 return endpoint.toString();
236 }
237
238 /**
239 * Generates endpoint URL by referring to scheme, ipAddress and port.
240 *
241 * @param apiConfig kubernetes API config
242 * @return generated endpoint URL
243 */
244 public static String endpoint(K8sApiConfig apiConfig) {
245 return endpoint(apiConfig.scheme(), apiConfig.ipAddress(), apiConfig.port());
246 }
247
248 /**
249 * Obtains workable kubernetes client.
250 *
251 * @param config kubernetes API config
252 * @return kubernetes client
253 */
254 public static KubernetesClient k8sClient(K8sApiConfig config) {
255 if (config == null) {
256 log.warn("Kubernetes API server config is empty.");
257 return null;
258 }
259
260 String endpoint = endpoint(config);
261
262 ConfigBuilder configBuilder = new ConfigBuilder().withMasterUrl(endpoint);
263
264 if (config.scheme() == K8sApiConfig.Scheme.HTTPS) {
265 configBuilder.withTrustCerts(true)
266 .withOauthToken(config.token())
267 .withCaCertData(config.caCertData())
268 .withClientCertData(config.clientCertData())
269 .withClientKeyData(config.clientKeyData());
270 }
271
272 return new DefaultKubernetesClient(configBuilder.build());
273 }
Jian Li3d1111e2019-02-22 02:02:13 +0900274
275 /**
276 * Obtains workable kubernetes client.
277 *
278 * @param service kubernetes API service
279 * @return kubernetes client
280 */
281 public static KubernetesClient k8sClient(K8sApiConfigService service) {
282 K8sApiConfig config =
283 service.apiConfigs().stream().findAny().orElse(null);
284 if (config == null) {
285 log.error("Failed to find valid kubernetes API configuration.");
286 return null;
287 }
288
289 KubernetesClient client = k8sClient(config);
290
291 if (client == null) {
292 log.error("Failed to connect to kubernetes API server.");
293 return null;
294 }
295
296 return client;
297 }
Jian Li2cc2b632019-02-18 00:56:40 +0900298
299 /**
300 * Obtains the kubernetes node IP and kubernetes network gateway IP map.
301 *
302 * @param nodeService kubernetes node service
303 * @param networkService kubernetes network service
304 * @return kubernetes node IP and kubernetes network gateway IP map
305 */
306 public static Map<String, String> nodeIpGatewayIpMap(K8sNodeService nodeService,
307 K8sNetworkService networkService) {
308 Map<String, String> ipMap = Maps.newConcurrentMap();
309
310 nodeService.completeNodes().forEach(n -> {
311 K8sNetwork network = networkService.network(n.hostname());
312 if (network != null) {
313 ipMap.put(n.dataIp().toString(), network.gatewayIp().toString());
314 }
315 });
316
317 return ipMap;
318 }
Jian Li004526d2019-02-25 16:26:27 +0900319
320 /**
Jian Li73d3b6a2019-07-08 18:07:53 +0900321 * Returns a shifted IP address.
322 *
323 * @param ipAddress IP address to be shifted
324 * @param shiftPrefix A IP prefix used in shifted IP address
325 * @return shifted Ip address
326 */
327 public static String shiftIpDomain(String ipAddress, String shiftPrefix) {
328 String origIpPrefix = ipAddress.split("\\.")[0] + "." + ipAddress.split("\\.")[1];
329 return StringUtils.replace(ipAddress, origIpPrefix, shiftPrefix);
330 }
331
332 /**
Jian Li140d8a22019-04-24 23:41:44 +0900333 * Returns an unshifted IP address.
Jian Li004526d2019-02-25 16:26:27 +0900334 *
Jian Li140d8a22019-04-24 23:41:44 +0900335 * @param ipAddress IP address to be unshifted
336 * @param ipPrefix IP prefix which to be used for unshifting
337 * @param cidr a POD network CIDR
338 * @return unshifted IP address
Jian Li004526d2019-02-25 16:26:27 +0900339 */
Jian Li140d8a22019-04-24 23:41:44 +0900340 public static String unshiftIpDomain(String ipAddress,
341 String ipPrefix,
342 String cidr) {
Jian Li004526d2019-02-25 16:26:27 +0900343
Jian Li140d8a22019-04-24 23:41:44 +0900344 String origIpPrefix = cidr.split("\\.")[0] + "." + cidr.split("\\.")[1];
345 return StringUtils.replace(ipAddress, ipPrefix, origIpPrefix);
346 }
Jian Li004526d2019-02-25 16:26:27 +0900347
Jian Li140d8a22019-04-24 23:41:44 +0900348 /**
349 * Returns the B class IP prefix of the given CIDR.
350 *
351 * @param cidr CIDR
352 * @return IP prefix
353 */
354 public static String getBclassIpPrefixFromCidr(String cidr) {
355 if (cidr == null) {
356 return null;
357 }
358 return cidr.split("\\.")[0] + "." + cidr.split("\\.")[1];
359 }
Jian Li004526d2019-02-25 16:26:27 +0900360
Jian Li140d8a22019-04-24 23:41:44 +0900361 /**
362 * Returns the A class IP prefix of the given CIDR.
363 *
364 * @param cidr CIDR
365 * @return IP prefix
366 */
367 public static String getAclassIpPrefixFromCidr(String cidr) {
368 if (cidr == null) {
369 return null;
370 }
371 return cidr.split("\\.")[0];
372 }
373
374 /**
375 * Returns the map of port range.
376 *
377 * @param portMin minimum port number
378 * @param portMax maximum port number
379 * @return map of port range
380 */
381 public static Map<TpPort, TpPort> buildPortRangeMatches(int portMin, int portMax) {
382
383 boolean processing = true;
384 int start = portMin;
385 Map<TpPort, TpPort> portMaskMap = Maps.newHashMap();
386 while (processing) {
387 String minStr = Integer.toBinaryString(start);
388 String binStrMinPadded = STR_PADDING.substring(minStr.length()) + minStr;
389
390 int mask = testMasks(binStrMinPadded, start, portMax);
391 int maskStart = binLower(binStrMinPadded, mask);
392 int maskEnd = binHigher(binStrMinPadded, mask);
393
394 log.debug("start : {} port/mask = {} / {} ", start, getMask(mask), maskStart);
395 portMaskMap.put(TpPort.tpPort(maskStart), TpPort.tpPort(
396 Integer.parseInt(Objects.requireNonNull(getMask(mask)), PORT_RADIX)));
397
398 start = maskEnd + 1;
399 if (start > portMax) {
400 processing = false;
401 }
402 }
403
404 return portMaskMap;
405 }
406
Jian Lie1a5b8f2019-07-23 17:13:19 +0900407 /**
408 * Returns the namespace hash value by given POD IP.
409 *
410 * @param k8sPodService kubernetes POD service
411 * @param k8sNamespaceService kubernetes namespace service
412 * @param podIp POD IP address
413 * @return namespace hash value
414 */
415 public static Integer namespaceHashByPodIp(K8sPodService k8sPodService,
416 K8sNamespaceService k8sNamespaceService,
417 String podIp) {
418 String ns = k8sPodService.pods().stream()
419 .filter(pod -> pod.getStatus().getPodIP() != null)
420 .filter(pod -> pod.getStatus().getPodIP().equals(podIp))
421 .map(pod -> pod.getMetadata().getNamespace())
422 .findAny().orElse(null);
423
424 if (ns != null) {
425 return k8sNamespaceService.namespaces().stream()
426 .filter(n -> n.getMetadata().getName().equals(ns))
427 .map(Namespace::hashCode).findAny().orElse(null);
428 } else {
429 return null;
430 }
431 }
432
433 /**
434 * Returns the namespace hash value by given service IP.
435 *
436 * @param k8sServiceService kubernetes service service
437 * @param k8sNamespaceService kubernetes namespace service
438 * @param serviceIp service IP address
439 * @return namespace hash value
440 */
441 public static int namespaceHashByServiceIp(K8sServiceService k8sServiceService,
442 K8sNamespaceService k8sNamespaceService,
443 String serviceIp) {
444 String ns = k8sServiceService.services().stream()
445 .filter(service -> service.getSpec().getClusterIP() != null)
446 .filter(service -> service.getSpec().getClusterIP().equalsIgnoreCase(serviceIp))
447 .map(service -> service.getMetadata().getNamespace())
448 .findAny().orElse(null);
449
450 if (ns != null) {
451 return namespaceHashByNamespace(k8sNamespaceService, ns);
452 } else {
453 return DEFAULT_NAMESPACE_HASH;
454 }
455 }
456
457 /**
458 * Returns the namespace hash value by given namespace name.
459 *
460 * @param k8sNamespaceService kubernetes namespace service
461 * @param ns namespace name
462 * @return namespace hash value
463 */
464 public static int namespaceHashByNamespace(K8sNamespaceService k8sNamespaceService,
465 String ns) {
466
467 return k8sNamespaceService.namespaces().stream()
468 .filter(n -> n.getMetadata().getName() != null)
469 .filter(n -> n.getMetadata().getName().equalsIgnoreCase(ns))
470 .map(Namespace::hashCode).findAny().orElse(DEFAULT_NAMESPACE_HASH);
471 }
472
473 /**
474 * Returns POD instance by POD IP address.
475 *
476 * @param podService kubernetes POD service
477 * @param podIp POD IP address
478 * @return POD instance
479 */
480 public static Pod podByIp(K8sPodService podService, String podIp) {
481 return podService.pods().stream()
482 .filter(pod -> pod.getStatus().getPodIP() != null)
483 .filter(pod -> pod.getStatus().getPodIP().equals(podIp))
484 .findAny().orElse(null);
485 }
486
487 /**
488 * Returns the container port number by given container port name.
489 *
490 * @param pod kubernetes POD
491 * @param portName port name
492 * @return container port number,
493 * return 0 if there is no port number mapped with the given port name
494 */
495 public static int portNumberByName(Pod pod, String portName) {
Jian Li5cf3b002019-08-30 17:57:53 +0900496
497 if (pod == null || pod.getSpec() == null) {
498 return 0;
499 }
500
Jian Lie1a5b8f2019-07-23 17:13:19 +0900501 for (Container container : pod.getSpec().getContainers()) {
502 for (ContainerPort cp : container.getPorts()) {
503 if (cp.getName() != null && cp.getName().equals(portName)) {
504 return cp.getContainerPort();
505 }
506 }
507 }
508
509 return 0;
510 }
511
Jian Li4bd6f2b2019-08-16 21:39:27 +0900512 /**
513 * Synchronizes port from kubernetes POD.
514 *
515 * @param pod kubernetes POD
516 * @param adminService admin service
517 */
518 public static void syncPortFromPod(Pod pod, K8sNetworkAdminService adminService) {
519 Map<String, String> annotations = pod.getMetadata().getAnnotations();
520 if (annotations != null && !annotations.isEmpty() &&
521 annotations.get(PORT_ID) != null) {
522 String portId = annotations.get(PORT_ID);
523
524 K8sPort oldPort = adminService.port(portId);
525
526 String networkId = annotations.get(NETWORK_ID);
527 DeviceId deviceId = DeviceId.deviceId(annotations.get(DEVICE_ID));
528 PortNumber portNumber = PortNumber.portNumber(annotations.get(PORT_NUMBER));
529 IpAddress ipAddress = IpAddress.valueOf(annotations.get(IP_ADDRESS));
530 MacAddress macAddress = MacAddress.valueOf(annotations.get(MAC_ADDRESS));
531
532 K8sPort newPort = DefaultK8sPort.builder()
533 .portId(portId)
534 .networkId(networkId)
535 .deviceId(deviceId)
536 .ipAddress(ipAddress)
537 .macAddress(macAddress)
538 .portNumber(portNumber)
539 .state(INACTIVE)
540 .build();
541
542 if (oldPort == null) {
543 adminService.createPort(newPort);
544 } else {
545 adminService.updatePort(newPort);
546 }
547 }
548 }
549
Jian Lia6f58382019-12-16 14:22:13 +0900550 /**
551 * Generates string format based on the given string length list.
552 *
553 * @param stringLengths a list of string lengths
554 * @return string format (e.g., %-28s%-15s%-24s%-20s%-15s)
555 */
556 public static String genFormatString(List<Integer> stringLengths) {
557 StringBuilder fsb = new StringBuilder();
558 stringLengths.forEach(length -> {
559 fsb.append("%-");
560 fsb.append(length);
561 fsb.append("s");
562 });
563 return fsb.toString();
564 }
565
Jian Li140d8a22019-04-24 23:41:44 +0900566 private static int binLower(String binStr, int bits) {
567 StringBuilder outBin = new StringBuilder(
568 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
569 for (int i = 0; i < bits; i++) {
570 outBin.append(STR_ZERO);
571 }
572
573 return Integer.parseInt(outBin.toString(), MASK_RADIX);
574 }
575
576 private static int binHigher(String binStr, int bits) {
577 StringBuilder outBin = new StringBuilder(
578 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
579 for (int i = 0; i < bits; i++) {
580 outBin.append(STR_ONE);
581 }
582
583 return Integer.parseInt(outBin.toString(), MASK_RADIX);
584 }
585
586 private static int testMasks(String binStr, int start, int end) {
587 int mask = MASK_BEGIN_IDX;
588 for (; mask <= MASK_MAX_IDX; mask++) {
589 int maskStart = binLower(binStr, mask);
590 int maskEnd = binHigher(binStr, mask);
591 if (maskStart < start || maskEnd > end) {
592 return mask - 1;
593 }
594 }
595
596 return mask;
597 }
598
599 private static String getMask(int bits) {
600 switch (bits) {
601 case 0: return "ffff";
602 case 1: return "fffe";
603 case 2: return "fffc";
604 case 3: return "fff8";
605 case 4: return "fff0";
606 case 5: return "ffe0";
607 case 6: return "ffc0";
608 case 7: return "ff80";
609 case 8: return "ff00";
610 case 9: return "fe00";
611 case 10: return "fc00";
612 case 11: return "f800";
613 case 12: return "f000";
614 case 13: return "e000";
615 case 14: return "c000";
616 case 15: return "8000";
617 case 16: return "0000";
618 default: return null;
619 }
Jian Li004526d2019-02-25 16:26:27 +0900620 }
Jian Libde20bf2019-01-25 17:34:43 +0900621}