2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.openflowplugin.impl.util;
11 import java.math.BigInteger;
12 import java.util.StringTokenizer;
13 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
14 import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
15 import org.opendaylight.openflowplugin.openflow.md.util.OpenflowPortsUtil;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanPcp;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpSourceHardwareAddress;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddress;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestination;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSource;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetType;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4Match;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv6Match;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatch;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Metadata;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.ProtocolMatchFields;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.TcpFlagMatch;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Tunnel;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.TunnelIpv4Match;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.SctpMatch;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatch;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.protocol.match.fields.Pbb;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanId;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
54 * Created by Martin Bobak <mbobak@cisco.com> on 8.4.2015.
56 public final class HashUtil {
58 private static final Logger LOG = LoggerFactory.getLogger(HashUtil.class);
59 private static final int BASE_16 = 16;
60 private static final int BASE_10 = 10;
61 private static final long IPV6_TOKENS_COUNT = 8;
62 public static final String IPV6_TOKEN = ":0000";
66 throw new IllegalStateException("This class should not be instantiated.");
69 public static long calculateEthernetMatchHash(EthernetMatch ethernetMatch) {
72 EthernetType ethernetType = ethernetMatch.getEthernetType();
73 if (null != ethernetType) {
74 hash += ethernetType.getType().getValue();
77 EthernetDestination ethernetDestination = ethernetMatch.getEthernetDestination();
78 if (null != ethernetDestination) {
79 hash += calculateEthernetDestinationHash(ethernetDestination);
82 EthernetSource ethernetSource = ethernetMatch.getEthernetSource();
83 if (null != ethernetSource) {
84 hash += calculateEthenetSourceHash(ethernetSource);
90 public static long calculateEthenetSourceHash(EthernetSource ethernetSource) {
91 long hash = calculateMacAddressHash(ethernetSource.getAddress());
92 hash += calculateMacAddressHash(ethernetSource.getMask());
96 public static long calculateEthernetDestinationHash(EthernetDestination ethernetDestination) {
97 long hash = calculateMacAddressHash(ethernetDestination.getAddress());
98 hash += calculateMacAddressHash(ethernetDestination.getMask());
102 public static long calculateMacAddressHash(MacAddress macAddress) {
105 if (null != macAddress) {
106 StringTokenizer stringTokenizer = new StringTokenizer(macAddress.getValue(), ":");
107 hash = parseTokens(stringTokenizer, BASE_16, 8);
112 public static long calculateMatchHash(final Match match, DeviceContext deviceContext) {
117 if (null != match.getEthernetMatch()) {
119 subHash += calculateEthernetMatchHash(match.getEthernetMatch());
122 if (null != match.getIcmpv4Match()) {
124 subHash += calculateIcmpV4MatchHash(match.getIcmpv4Match());
127 if (null != match.getIcmpv6Match()) {
129 subHash += calculateIcmpV6MatchHash(match.getIcmpv6Match());
132 if (null != match.getInPhyPort()) {
134 subHash += calculateNodeConnectorIdHash(match.getInPhyPort(), deviceContext);
137 if (null != match.getInPort()) {
139 subHash += calculateNodeConnectorIdHash(match.getInPort(), deviceContext);
142 if (null != match.getIpMatch()) {
144 subHash += calculateIpMatchHash(match.getIpMatch());
147 if (null != match.getLayer3Match()) {
149 subHash += calculateLayer3MatchHash(match.getLayer3Match());
152 if (null != match.getLayer4Match()) {
154 subHash += calculateLayer4MatchHash(match.getLayer4Match());
157 if (null != match.getIcmpv6Match()) {
159 subHash += calculateIcmpv6MatchHash(match.getIcmpv6Match());
162 if (null != match.getMetadata()) {
164 subHash += calculateMetadataHash(match.getMetadata());
167 if (null != match.getProtocolMatchFields()) {
169 subHash += calculateProtocolMatchFieldsHash(match.getProtocolMatchFields());
172 if (null != match.getTcpFlagMatch()) {
174 subHash += calculateTcpFlagMatch(match.getTcpFlagMatch());
177 if (null != match.getVlanMatch()) {
179 subHash += calculateVlanMatchHash(match.getVlanMatch());
182 if (null != match.getTunnel()) {
184 subHash += calculateTunnelHash(match.getTunnel());
187 return hash + subHash;
190 private static long calculateTunnelHash(final Tunnel tunnel) {
192 BigInteger tunnelId = tunnel.getTunnelId();
193 if (null != tunnelId) {
194 hash += tunnelId.intValue();
197 BigInteger tunnelMask = tunnel.getTunnelMask();
198 if (null != tunnelMask) {
199 hash += tunnelMask.intValue();
204 private static long calculateVlanMatchHash(final VlanMatch vlanMatch) {
207 VlanId vlanId = vlanMatch.getVlanId();
208 if (null != vlanId) {
209 hash += vlanId.getVlanId().getValue().intValue();
212 VlanPcp vlanPcp = vlanMatch.getVlanPcp();
213 if (null != vlanPcp) {
214 hash += vlanPcp.getValue().shortValue();
220 private static long calculateTcpFlagMatch(final TcpFlagMatch tcpFlagMatch) {
221 long hash = tcpFlagMatch.getTcpFlag().intValue();
225 private static long calculateProtocolMatchFieldsHash(final ProtocolMatchFields protocolMatchFields) {
227 Short mplsBos = protocolMatchFields.getMplsBos();
228 if (null != mplsBos) {
229 hash += mplsBos.intValue();
231 Short mplsTc = protocolMatchFields.getMplsTc();
232 if (null != mplsTc) {
233 hash += mplsTc.intValue();
235 Pbb pbb = protocolMatchFields.getPbb();
237 if (null != pbb.getPbbIsid()) {
238 hash += pbb.getPbbIsid().intValue();
240 if (null != pbb.getPbbMask()) {
241 hash += pbb.getPbbMask().intValue();
244 Long mplsLabel = protocolMatchFields.getMplsLabel();
245 if (null != mplsLabel) {
246 hash += mplsLabel.intValue();
251 private static long calculateMetadataHash(final Metadata metadata) {
252 long hash = metadata.getMetadata().intValue();
253 if (null != metadata.getMetadataMask()) {
254 hash += metadata.getMetadataMask().intValue();
259 private static long calculateIcmpv6MatchHash(final Icmpv6Match icmpv6Match) {
260 long hash = icmpv6Match.getIcmpv6Code().intValue();
261 hash += icmpv6Match.getIcmpv6Type().intValue();
265 private static long calculateLayer4MatchHash(final Layer4Match layer4Match) {
267 if (layer4Match instanceof SctpMatch) {
268 hash += calculateSctpMatchHash((SctpMatch) layer4Match);
271 if (layer4Match instanceof TcpMatch) {
272 hash += calculateTcpMatchHash((TcpMatch) layer4Match);
274 if (layer4Match instanceof UdpMatch) {
275 hash += calculateUdpMatchHash((UdpMatch) layer4Match);
280 private static long calculateUdpMatchHash(final UdpMatch layer4Match) {
285 private static long calculateTcpMatchHash(final TcpMatch layer4Match) {
287 PortNumber sourcePort = layer4Match.getTcpSourcePort();
288 if (null != sourcePort) {
289 hash += sourcePort.getValue().intValue();
292 PortNumber destinationPort = layer4Match.getTcpDestinationPort();
293 if (null != destinationPort) {
294 hash += destinationPort.getValue().intValue();
299 private static long calculateSctpMatchHash(final SctpMatch layer4Match) {
302 PortNumber portNumber = layer4Match.getSctpDestinationPort();
303 if (null != portNumber) {
304 hash += portNumber.getValue().intValue();
307 PortNumber sourcePort = layer4Match.getSctpSourcePort();
308 if (null != sourcePort) {
309 hash += sourcePort.getValue().intValue();
314 private static long calculateLayer3MatchHash(final Layer3Match layer3Match) {
316 if (layer3Match instanceof ArpMatch) {
317 hash += calculateArpMatchHash((ArpMatch) layer3Match);
319 if (layer3Match instanceof Ipv4Match) {
320 hash += calculateIpv4MatchHash((Ipv4Match) layer3Match);
322 if (layer3Match instanceof Ipv6Match) {
323 hash += calculateIpv6MatchHash((Ipv6Match) layer3Match);
326 if (layer3Match instanceof TunnelIpv4Match) {
327 hash += calculateTunnelIpv4Hash((TunnelIpv4Match) layer3Match);
332 private static long calculateTunnelIpv4Hash(final TunnelIpv4Match layer3Match) {
333 Ipv4Prefix tunnelIpv4Destination = layer3Match.getTunnelIpv4Destination();
334 long hash = calculateIpv4PrefixHash(tunnelIpv4Destination);
335 Ipv4Prefix tunnelIpv4Source = layer3Match.getTunnelIpv4Source();
336 hash += calculateIpv4PrefixHash(tunnelIpv4Source);
340 private static long calculateIpv6MatchHash(final Ipv6Match layer3Match) {
342 Ipv6Prefix ipv6Destination = layer3Match.getIpv6Destination();
343 if (null != ipv6Destination) {
344 hash += calculateIpv6PrefixHash(ipv6Destination);
347 if (null != layer3Match.getIpv6Source()) {
348 hash += calculateIpv6PrefixHash(layer3Match.getIpv6Source());
351 if (null != layer3Match.getIpv6ExtHeader()) {
352 hash += layer3Match.getIpv6ExtHeader().getIpv6Exthdr();
353 hash += layer3Match.getIpv6ExtHeader().getIpv6ExthdrMask();
356 if (null != layer3Match.getIpv6NdSll()) {
357 hash += calculateMacAddressHash(layer3Match.getIpv6NdSll());
359 if (null != layer3Match.getIpv6NdTll()) {
360 hash += calculateMacAddressHash(layer3Match.getIpv6NdTll());
362 if (null != layer3Match.getIpv6NdTarget()) {
363 hash += calculateIpv6AddressHash(layer3Match.getIpv6NdTarget());
369 public static long calculateIpv6PrefixHash(final Ipv6Prefix ipv6Prefix) {
371 StringTokenizer stringTokenizer = getStringTokenizerWithFullAddressString(ipv6Prefix.getValue());
373 long hash = parseTokens(stringTokenizer, BASE_16, 16);
377 public static long calculateIpv6AddressHash(final Ipv6Address ipv6Address) {
379 StringTokenizer stringTokenizer = getStringTokenizerWithFullAddressString(ipv6Address.getValue());
381 long hash = parseTokens(stringTokenizer, BASE_16, 16);
385 private static StringTokenizer getStringTokenizerWithFullAddressString(String value) {
386 String ipv6Value = value.replace("::", ":0000:");
387 StringTokenizer stringTokenizer = new StringTokenizer(ipv6Value, ":");
389 long delta = IPV6_TOKENS_COUNT - stringTokenizer.countTokens();
391 StringBuffer additions = new StringBuffer();
395 additions.append(IPV6_TOKEN);
398 if (ipv6Value.contains("/")) {
399 ipv6Value = ipv6Value.replace("/", additions.toString() + "/");
401 ipv6Value += additions.toString();
403 stringTokenizer = new StringTokenizer(ipv6Value, ":");
405 return stringTokenizer;
408 private static long calculateStopperBasedOnMaskValue(final Ipv6Prefix ipv6Prefix, long bitsBase) {
409 double maskValue = extractMask(ipv6Prefix);
410 double bitCount = maskValue / bitsBase;
411 return (int) Math.ceil(bitCount);
414 private static long extractMask(final Ipv6Prefix ipv6Prefix) {
415 StringTokenizer maskTokenizer = new StringTokenizer(ipv6Prefix.getValue(), "/");
417 if (maskTokenizer.countTokens() > 1) {
418 maskTokenizer.nextToken();
419 mask = Integer.parseInt(maskTokenizer.nextToken());
424 private static long parseTokens(final StringTokenizer stringTokenizer, int base, int bitShift) {
425 return parseTokens(stringTokenizer, 0, base, bitShift);
428 private static long parseTokens(final StringTokenizer stringTokenizer, long stopper, int base, int bitShift) {
430 if (stringTokenizer.countTokens() > 0) {
432 while (stringTokenizer.hasMoreTokens()) {
433 String token = stringTokenizer.nextToken();
436 if (token.equals("")) {
440 if (token.contains("/")) {
441 StringTokenizer tokenizer = new StringTokenizer(token, "/");
442 hash += parseTokens(tokenizer, stopper, base, bitShift);
444 hash += Long.parseLong(token, base) << (bitShift * step);
445 if (stopper > 0 && step == stopper) {
454 private static long calculateIpv4MatchHash(final Ipv4Match layer3Match) {
456 Ipv4Prefix ipv4Destination = layer3Match.getIpv4Destination();
457 if (null != ipv4Destination) {
458 hash += calculateIpv4PrefixHash(ipv4Destination);
461 Ipv4Prefix ipv4Source = layer3Match.getIpv4Source();
463 if (null != ipv4Source) {
464 hash += calculateIpv4PrefixHash(ipv4Source);
467 //TODO : add calculation of hashes for augmentations
471 private static long calculateArpMatchHash(final ArpMatch layer3Match) {
473 Integer arpOp = layer3Match.getArpOp();
475 hash += arpOp.intValue();
477 ArpSourceHardwareAddress arpSourceHardwareAddress = layer3Match.getArpSourceHardwareAddress();
478 if (null != arpSourceHardwareAddress) {
479 hash += calculateMacAddressHash(arpSourceHardwareAddress.getAddress());
480 hash += calculateMacAddressHash(arpSourceHardwareAddress.getMask());
483 Ipv4Prefix sourceTransportAddress = layer3Match.getArpSourceTransportAddress();
484 if (null != sourceTransportAddress) {
485 hash += calculateIpv4PrefixHash(sourceTransportAddress);
488 ArpTargetHardwareAddress arpTargetHardwareAddress = layer3Match.getArpTargetHardwareAddress();
489 if (null != arpTargetHardwareAddress) {
490 hash += calculateMacAddressHash(arpTargetHardwareAddress.getAddress());
491 hash += calculateMacAddressHash(arpTargetHardwareAddress.getMask());
494 Ipv4Prefix targetTransportAddress = layer3Match.getArpTargetTransportAddress();
495 if (null != targetTransportAddress) {
496 hash += calculateIpv4PrefixHash(targetTransportAddress);
502 public static long calculateIpv4PrefixHash(final Ipv4Prefix ipv4Prefix) {
504 StringTokenizer prefixAsArray = new StringTokenizer(ipv4Prefix.getValue(), "/");
505 if (prefixAsArray.countTokens() == 2) {
506 String address = prefixAsArray.nextToken();
507 Long mask = Long.parseLong(prefixAsArray.nextToken());
508 long numberOfAddressPartsToUse = (int) Math.ceil(mask.doubleValue() / 8);
509 hash += calculateIpAdressHash(address, numberOfAddressPartsToUse, BASE_10);
510 hash += mask.shortValue();
516 private static long calculateIpAdressHash(final String address, long numberOfParts, int base) {
517 StringTokenizer stringTokenizer = new StringTokenizer(address, ".");
518 long hash = parseTokens(stringTokenizer, numberOfParts, base, 8);
522 private static long calculateIpMatchHash(final IpMatch ipMatch) {
524 Short ipEcn = ipMatch.getIpEcn();
526 hash += ipEcn.shortValue();
528 Short ipProtocol = ipMatch.getIpProtocol();
529 if (null != ipProtocol) {
533 Short ipDscp = ipMatch.getIpDscp().getValue();
534 if (null != ipDscp) {
538 IpVersion ipVersion = ipMatch.getIpProto();
539 if (null != ipVersion) {
540 hash += ipVersion.getIntValue();
545 private static long calculateNodeConnectorIdHash(final NodeConnectorId inPhyPort, DeviceContext deviceContext) {
547 short version = deviceContext.getDeviceState().getVersion();
548 Long portFromLogicalName = OpenflowPortsUtil.getPortFromLogicalName(OpenflowVersion.get(version), inPhyPort.getValue());
549 hash += portFromLogicalName.intValue();
553 private static long calculateIcmpV6MatchHash(final Icmpv6Match icmpv6Match) {
555 if (null != icmpv6Match.getIcmpv6Code()) {
556 hash += icmpv6Match.getIcmpv6Code();
558 if (null != icmpv6Match.getIcmpv6Type()) {
559 hash += icmpv6Match.getIcmpv6Type();
564 public static long calculateIcmpV4MatchHash(final Icmpv4Match icmpv4Match) {
566 if (null != icmpv4Match.getIcmpv4Code()) {
567 hash += icmpv4Match.getIcmpv4Code();
569 if (null != icmpv4Match.getIcmpv4Type()) {
570 hash += icmpv4Match.getIcmpv4Type();