blob: dfe70f2ff5653304e3384b9f35c952a253f29447 [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
Jian Li9b199162019-02-10 18:00:35 +090055import java.util.Arrays;
56import java.util.HashSet;
Jian Lidad23432019-12-16 14:22:13 +090057import java.util.List;
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 Li1ea027142019-08-26 23:19:38 +0900173 log.debug("JsonParseException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900174 } catch (JsonMappingException e) {
Jian Li1ea027142019-08-26 23:19:38 +0900175 log.debug("JsonMappingException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900176 } catch (JsonProcessingException e) {
Jian Li1ea027142019-08-26 23:19:38 +0900177 log.debug("JsonProcessingException", e);
Jian Libde20bf2019-01-25 17:34:43 +0900178 }
179 return null;
180 }
Jian Li9b199162019-02-10 18:00:35 +0900181
182 /**
183 * Obtains valid IP addresses of the given subnet.
184 *
185 * @param cidr CIDR
186 * @return set of IP addresses
187 */
188 public static Set<IpAddress> getSubnetIps(String cidr) {
189 SubnetUtils utils = new SubnetUtils(cidr);
Jian Li7970b712019-05-03 20:58:21 +0900190 utils.setInclusiveHostCount(false);
Jian Li9b199162019-02-10 18:00:35 +0900191 SubnetUtils.SubnetInfo info = utils.getInfo();
192 Set<String> allAddresses =
193 new HashSet<>(Arrays.asList(info.getAllAddresses()));
194
195 if (allAddresses.size() > 2) {
Jian Li7970b712019-05-03 20:58:21 +0900196 allAddresses.remove(info.getLowAddress());
197 allAddresses.remove(info.getHighAddress());
Jian Li9b199162019-02-10 18:00:35 +0900198 }
199
200 return allAddresses.stream()
201 .map(IpAddress::valueOf).collect(Collectors.toSet());
202 }
Jian Li85387732019-02-19 23:56:18 +0900203
204 /**
Jian Li2cc2b632019-02-18 00:56:40 +0900205 * Obtains flow group key from the given id.
206 *
207 * @param groupId flow group identifier
208 * @return flow group key
209 */
210 public static GroupKey getGroupKey(int groupId) {
211 return new DefaultGroupKey((Integer.toString(groupId)).getBytes());
212 }
213
214 /**
Jian Li85387732019-02-19 23:56:18 +0900215 * Generates endpoint URL by referring to scheme, ipAddress and port.
216 *
217 * @param scheme scheme
218 * @param ipAddress IP address
219 * @param port port number
220 * @return generated endpoint URL
221 */
222 public static String endpoint(K8sApiConfig.Scheme scheme, IpAddress ipAddress, int port) {
223 StringBuilder endpoint = new StringBuilder();
224 String protocol = StringUtils.lowerCase(scheme.name());
225
226 endpoint.append(protocol);
227 endpoint.append(COLON_SLASH);
228 endpoint.append(ipAddress.toString());
229 endpoint.append(COLON);
230 endpoint.append(port);
231
232 return endpoint.toString();
233 }
234
235 /**
236 * Generates endpoint URL by referring to scheme, ipAddress and port.
237 *
238 * @param apiConfig kubernetes API config
239 * @return generated endpoint URL
240 */
241 public static String endpoint(K8sApiConfig apiConfig) {
242 return endpoint(apiConfig.scheme(), apiConfig.ipAddress(), apiConfig.port());
243 }
244
245 /**
246 * Obtains workable kubernetes client.
247 *
248 * @param config kubernetes API config
249 * @return kubernetes client
250 */
251 public static KubernetesClient k8sClient(K8sApiConfig config) {
252 if (config == null) {
253 log.warn("Kubernetes API server config is empty.");
254 return null;
255 }
256
257 String endpoint = endpoint(config);
258
259 ConfigBuilder configBuilder = new ConfigBuilder().withMasterUrl(endpoint);
260
261 if (config.scheme() == K8sApiConfig.Scheme.HTTPS) {
262 configBuilder.withTrustCerts(true)
263 .withOauthToken(config.token())
264 .withCaCertData(config.caCertData())
265 .withClientCertData(config.clientCertData())
266 .withClientKeyData(config.clientKeyData());
267 }
268
269 return new DefaultKubernetesClient(configBuilder.build());
270 }
Jian Li3d1111e2019-02-22 02:02:13 +0900271
272 /**
273 * Obtains workable kubernetes client.
274 *
275 * @param service kubernetes API service
276 * @return kubernetes client
277 */
278 public static KubernetesClient k8sClient(K8sApiConfigService service) {
279 K8sApiConfig config =
280 service.apiConfigs().stream().findAny().orElse(null);
281 if (config == null) {
282 log.error("Failed to find valid kubernetes API configuration.");
283 return null;
284 }
285
286 KubernetesClient client = k8sClient(config);
287
288 if (client == null) {
289 log.error("Failed to connect to kubernetes API server.");
290 return null;
291 }
292
293 return client;
294 }
Jian Li2cc2b632019-02-18 00:56:40 +0900295
296 /**
297 * Obtains the kubernetes node IP and kubernetes network gateway IP map.
298 *
299 * @param nodeService kubernetes node service
300 * @param networkService kubernetes network service
301 * @return kubernetes node IP and kubernetes network gateway IP map
302 */
303 public static Map<String, String> nodeIpGatewayIpMap(K8sNodeService nodeService,
304 K8sNetworkService networkService) {
305 Map<String, String> ipMap = Maps.newConcurrentMap();
306
307 nodeService.completeNodes().forEach(n -> {
308 K8sNetwork network = networkService.network(n.hostname());
309 if (network != null) {
310 ipMap.put(n.dataIp().toString(), network.gatewayIp().toString());
311 }
312 });
313
314 return ipMap;
315 }
Jian Li004526d2019-02-25 16:26:27 +0900316
317 /**
Jian Li73d3b6a2019-07-08 18:07:53 +0900318 * Returns a shifted IP address.
319 *
320 * @param ipAddress IP address to be shifted
321 * @param shiftPrefix A IP prefix used in shifted IP address
322 * @return shifted Ip address
323 */
324 public static String shiftIpDomain(String ipAddress, String shiftPrefix) {
325 String origIpPrefix = ipAddress.split("\\.")[0] + "." + ipAddress.split("\\.")[1];
326 return StringUtils.replace(ipAddress, origIpPrefix, shiftPrefix);
327 }
328
329 /**
Jian Li140d8a22019-04-24 23:41:44 +0900330 * Returns an unshifted IP address.
Jian Li004526d2019-02-25 16:26:27 +0900331 *
Jian Li140d8a22019-04-24 23:41:44 +0900332 * @param ipAddress IP address to be unshifted
333 * @param ipPrefix IP prefix which to be used for unshifting
334 * @param cidr a POD network CIDR
335 * @return unshifted IP address
Jian Li004526d2019-02-25 16:26:27 +0900336 */
Jian Li140d8a22019-04-24 23:41:44 +0900337 public static String unshiftIpDomain(String ipAddress,
338 String ipPrefix,
339 String cidr) {
Jian Li004526d2019-02-25 16:26:27 +0900340
Jian Li140d8a22019-04-24 23:41:44 +0900341 String origIpPrefix = cidr.split("\\.")[0] + "." + cidr.split("\\.")[1];
342 return StringUtils.replace(ipAddress, ipPrefix, origIpPrefix);
343 }
Jian Li004526d2019-02-25 16:26:27 +0900344
Jian Li140d8a22019-04-24 23:41:44 +0900345 /**
346 * Returns the B class IP prefix of the given CIDR.
347 *
348 * @param cidr CIDR
349 * @return IP prefix
350 */
351 public static String getBclassIpPrefixFromCidr(String cidr) {
352 if (cidr == null) {
353 return null;
354 }
355 return cidr.split("\\.")[0] + "." + cidr.split("\\.")[1];
356 }
Jian Li004526d2019-02-25 16:26:27 +0900357
Jian Li140d8a22019-04-24 23:41:44 +0900358 /**
359 * Returns the A class IP prefix of the given CIDR.
360 *
361 * @param cidr CIDR
362 * @return IP prefix
363 */
364 public static String getAclassIpPrefixFromCidr(String cidr) {
365 if (cidr == null) {
366 return null;
367 }
368 return cidr.split("\\.")[0];
369 }
370
371 /**
372 * Returns the map of port range.
373 *
374 * @param portMin minimum port number
375 * @param portMax maximum port number
376 * @return map of port range
377 */
378 public static Map<TpPort, TpPort> buildPortRangeMatches(int portMin, int portMax) {
379
380 boolean processing = true;
381 int start = portMin;
382 Map<TpPort, TpPort> portMaskMap = Maps.newHashMap();
383 while (processing) {
384 String minStr = Integer.toBinaryString(start);
385 String binStrMinPadded = STR_PADDING.substring(minStr.length()) + minStr;
386
387 int mask = testMasks(binStrMinPadded, start, portMax);
388 int maskStart = binLower(binStrMinPadded, mask);
389 int maskEnd = binHigher(binStrMinPadded, mask);
390
391 log.debug("start : {} port/mask = {} / {} ", start, getMask(mask), maskStart);
392 portMaskMap.put(TpPort.tpPort(maskStart), TpPort.tpPort(
393 Integer.parseInt(Objects.requireNonNull(getMask(mask)), PORT_RADIX)));
394
395 start = maskEnd + 1;
396 if (start > portMax) {
397 processing = false;
398 }
399 }
400
401 return portMaskMap;
402 }
403
Jian Lie1a5b8f2019-07-23 17:13:19 +0900404 /**
405 * Returns the namespace hash value by given POD IP.
406 *
407 * @param k8sPodService kubernetes POD service
408 * @param k8sNamespaceService kubernetes namespace service
409 * @param podIp POD IP address
410 * @return namespace hash value
411 */
412 public static Integer namespaceHashByPodIp(K8sPodService k8sPodService,
413 K8sNamespaceService k8sNamespaceService,
414 String podIp) {
415 String ns = k8sPodService.pods().stream()
416 .filter(pod -> pod.getStatus().getPodIP() != null)
417 .filter(pod -> pod.getStatus().getPodIP().equals(podIp))
418 .map(pod -> pod.getMetadata().getNamespace())
419 .findAny().orElse(null);
420
421 if (ns != null) {
422 return k8sNamespaceService.namespaces().stream()
423 .filter(n -> n.getMetadata().getName().equals(ns))
424 .map(Namespace::hashCode).findAny().orElse(null);
425 } else {
426 return null;
427 }
428 }
429
430 /**
431 * Returns the namespace hash value by given service IP.
432 *
433 * @param k8sServiceService kubernetes service service
434 * @param k8sNamespaceService kubernetes namespace service
435 * @param serviceIp service IP address
436 * @return namespace hash value
437 */
438 public static int namespaceHashByServiceIp(K8sServiceService k8sServiceService,
439 K8sNamespaceService k8sNamespaceService,
440 String serviceIp) {
441 String ns = k8sServiceService.services().stream()
442 .filter(service -> service.getSpec().getClusterIP() != null)
443 .filter(service -> service.getSpec().getClusterIP().equalsIgnoreCase(serviceIp))
444 .map(service -> service.getMetadata().getNamespace())
445 .findAny().orElse(null);
446
447 if (ns != null) {
448 return namespaceHashByNamespace(k8sNamespaceService, ns);
449 } else {
450 return DEFAULT_NAMESPACE_HASH;
451 }
452 }
453
454 /**
455 * Returns the namespace hash value by given namespace name.
456 *
457 * @param k8sNamespaceService kubernetes namespace service
458 * @param ns namespace name
459 * @return namespace hash value
460 */
461 public static int namespaceHashByNamespace(K8sNamespaceService k8sNamespaceService,
462 String ns) {
463
464 return k8sNamespaceService.namespaces().stream()
465 .filter(n -> n.getMetadata().getName() != null)
466 .filter(n -> n.getMetadata().getName().equalsIgnoreCase(ns))
467 .map(Namespace::hashCode).findAny().orElse(DEFAULT_NAMESPACE_HASH);
468 }
469
470 /**
471 * Returns POD instance by POD IP address.
472 *
473 * @param podService kubernetes POD service
474 * @param podIp POD IP address
475 * @return POD instance
476 */
477 public static Pod podByIp(K8sPodService podService, String podIp) {
478 return podService.pods().stream()
479 .filter(pod -> pod.getStatus().getPodIP() != null)
480 .filter(pod -> pod.getStatus().getPodIP().equals(podIp))
481 .findAny().orElse(null);
482 }
483
484 /**
485 * Returns the container port number by given container port name.
486 *
487 * @param pod kubernetes POD
488 * @param portName port name
489 * @return container port number,
490 * return 0 if there is no port number mapped with the given port name
491 */
492 public static int portNumberByName(Pod pod, String portName) {
Jian Lia5c80c62019-08-30 17:57:53 +0900493
494 if (pod == null || pod.getSpec() == null) {
495 return 0;
496 }
497
Jian Lie1a5b8f2019-07-23 17:13:19 +0900498 for (Container container : pod.getSpec().getContainers()) {
499 for (ContainerPort cp : container.getPorts()) {
500 if (cp.getName() != null && cp.getName().equals(portName)) {
501 return cp.getContainerPort();
502 }
503 }
504 }
505
506 return 0;
507 }
508
Jian Li4bd6f2b2019-08-16 21:39:27 +0900509 /**
510 * Synchronizes port from kubernetes POD.
511 *
512 * @param pod kubernetes POD
513 * @param adminService admin service
514 */
515 public static void syncPortFromPod(Pod pod, K8sNetworkAdminService adminService) {
516 Map<String, String> annotations = pod.getMetadata().getAnnotations();
517 if (annotations != null && !annotations.isEmpty() &&
518 annotations.get(PORT_ID) != null) {
519 String portId = annotations.get(PORT_ID);
520
521 K8sPort oldPort = adminService.port(portId);
522
523 String networkId = annotations.get(NETWORK_ID);
524 DeviceId deviceId = DeviceId.deviceId(annotations.get(DEVICE_ID));
525 PortNumber portNumber = PortNumber.portNumber(annotations.get(PORT_NUMBER));
526 IpAddress ipAddress = IpAddress.valueOf(annotations.get(IP_ADDRESS));
527 MacAddress macAddress = MacAddress.valueOf(annotations.get(MAC_ADDRESS));
528
529 K8sPort newPort = DefaultK8sPort.builder()
530 .portId(portId)
531 .networkId(networkId)
532 .deviceId(deviceId)
533 .ipAddress(ipAddress)
534 .macAddress(macAddress)
535 .portNumber(portNumber)
536 .state(INACTIVE)
537 .build();
538
539 if (oldPort == null) {
540 adminService.createPort(newPort);
541 } else {
542 adminService.updatePort(newPort);
543 }
544 }
545 }
546
Jian Lidad23432019-12-16 14:22:13 +0900547 /**
548 * Generates string format based on the given string length list.
549 *
550 * @param stringLengths a list of string lengths
551 * @return string format (e.g., %-28s%-15s%-24s%-20s%-15s)
552 */
553 public static String genFormatString(List<Integer> stringLengths) {
554 StringBuilder fsb = new StringBuilder();
555 stringLengths.forEach(length -> {
556 fsb.append("%-");
557 fsb.append(length);
558 fsb.append("s");
559 });
560 return fsb.toString();
561 }
562
Jian Li140d8a22019-04-24 23:41:44 +0900563 private static int binLower(String binStr, int bits) {
564 StringBuilder outBin = new StringBuilder(
565 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
566 for (int i = 0; i < bits; i++) {
567 outBin.append(STR_ZERO);
568 }
569
570 return Integer.parseInt(outBin.toString(), MASK_RADIX);
571 }
572
573 private static int binHigher(String binStr, int bits) {
574 StringBuilder outBin = new StringBuilder(
575 binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
576 for (int i = 0; i < bits; i++) {
577 outBin.append(STR_ONE);
578 }
579
580 return Integer.parseInt(outBin.toString(), MASK_RADIX);
581 }
582
583 private static int testMasks(String binStr, int start, int end) {
584 int mask = MASK_BEGIN_IDX;
585 for (; mask <= MASK_MAX_IDX; mask++) {
586 int maskStart = binLower(binStr, mask);
587 int maskEnd = binHigher(binStr, mask);
588 if (maskStart < start || maskEnd > end) {
589 return mask - 1;
590 }
591 }
592
593 return mask;
594 }
595
596 private static String getMask(int bits) {
597 switch (bits) {
598 case 0: return "ffff";
599 case 1: return "fffe";
600 case 2: return "fffc";
601 case 3: return "fff8";
602 case 4: return "fff0";
603 case 5: return "ffe0";
604 case 6: return "ffc0";
605 case 7: return "ff80";
606 case 8: return "ff00";
607 case 9: return "fe00";
608 case 10: return "fc00";
609 case 11: return "f800";
610 case 12: return "f000";
611 case 13: return "e000";
612 case 14: return "c000";
613 case 15: return "8000";
614 case 16: return "0000";
615 default: return null;
616 }
Jian Li004526d2019-02-25 16:26:27 +0900617 }
Jian Libde20bf2019-01-25 17:34:43 +0900618}