2 * Copyright (c) 2017 HPE, 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
8 package org.opendaylight.netvirt.statistics;
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.atomic.AtomicLong;
14 import org.opendaylight.genius.mdsalutil.ActionInfo;
15 import org.opendaylight.genius.mdsalutil.InstructionInfo;
16 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
17 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
18 import org.opendaylight.genius.mdsalutil.NwConstants;
19 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
20 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
21 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
22 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
23 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
24 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Source;
25 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Destination;
26 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Source;
27 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
28 import org.opendaylight.genius.mdsalutil.matches.MatchTcpDestinationPort;
29 import org.opendaylight.genius.mdsalutil.matches.MatchTcpSourcePort;
30 import org.opendaylight.genius.mdsalutil.matches.MatchUdpDestinationPort;
31 import org.opendaylight.genius.mdsalutil.matches.MatchUdpSourcePort;
32 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
33 import org.opendaylight.genius.utils.ServiceIndex;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.statistics.rev170120.EgressElementCountersRequestConfig;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.statistics.rev170120.IngressElementCountersRequestConfig;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
61 public final class CountersServiceUtils {
63 public static final Long COUNTERS_PULL_END = Long.valueOf(100000);
64 public static final Long COUNTERS_PULL_START = Long.valueOf(1);
65 public static final short COUNTER_TABLE_COUNTER_FLOW_PRIORITY = 50;
66 public static final short COUNTER_TABLE_DEFAULT_FLOW_PRIORITY = 1;
67 public static final BigInteger COOKIE_COUNTERS_BASE = new BigInteger("7000000", 16);
68 public static final short EGRESS_COUNTERS_DEFAULT_FLOW_PRIORITY = 50;
69 public static final short INGRESS_COUNTERS_DEFAULT_FLOW_PRIORITY = 2;
70 public static final short EGRESS_COUNTERS_SERVICE_INDEX =
71 ServiceIndex.getIndex(NwConstants.EGRESS_COUNTERS_SERVICE_NAME, NwConstants.EGRESS_COUNTERS_SERVICE_INDEX);
72 public static final short INGRESS_COUNTERS_SERVICE_INDEX = ServiceIndex
73 .getIndex(NwConstants.INGRESS_COUNTERS_SERVICE_NAME, NwConstants.INGRESS_COUNTERS_SERVICE_INDEX);
75 public static final String COUNTER_FLOW_NAME = "COUNTER";
76 public static final String COUNTERS_PULL_NAME = "CountersPull";
77 public static final String DEFAULT_EGRESS_COUNTER_FLOW_PREFIX = "Egress_Counters_Default";
78 public static final String DEFAULT_INGRESS_COUNTER_FLOW_PREFIX = "Ingress_Counters_Default";
79 public static final String EGRESS_COUNTER_RESULT_ID = "Incoming Traffic";
80 public static final String INGRESS_COUNTER_RESULT_ID = "Outgoing Traffic";
82 public static final InstanceIdentifier<EgressElementCountersRequestConfig> EECRC_IDENTIFIER =
83 InstanceIdentifier.builder(EgressElementCountersRequestConfig.class).build();
84 public static final InstanceIdentifier<IngressElementCountersRequestConfig> IECRC_IDENTIFIER =
85 InstanceIdentifier.builder(IngressElementCountersRequestConfig.class).build();
87 private static AtomicLong flowIdInc = new AtomicLong(2);
89 private CountersServiceUtils() { }
91 public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
92 BigInteger cookie, List<Instruction> instructions) {
93 StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
94 .setInstruction(instructions);
95 return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
96 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
97 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
100 public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short priority,
101 Class<? extends ServiceModeBase> mode) {
102 return InstanceIdentifier.builder(ServiceBindings.class)
103 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, mode))
104 .child(BoundServices.class, new BoundServicesKey(priority)).build();
107 public static MatchInfoBase buildLPortTagMatch(int lportTag, ElementCountersDirection direction) {
108 if (ElementCountersDirection.INGRESS.equals(direction)) {
109 return new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG);
110 } else if (ElementCountersDirection.EGRESS.equals(direction)) {
111 return new NxMatchRegister(NxmNxReg6.class, MetaDataUtil.getLportTagForReg6(lportTag).longValue(),
112 MetaDataUtil.getLportTagMaskForReg6());
117 public static List<InstructionInfo> getDispatcherTableResubmitInstructions(List<ActionInfo> actionsInfos,
118 ElementCountersDirection direction) {
119 short dispatcherTableId = NwConstants.LPORT_DISPATCHER_TABLE;
120 if (ElementCountersDirection.EGRESS.equals(direction)) {
121 dispatcherTableId = NwConstants.EGRESS_LPORT_DISPATCHER_TABLE;
124 List<InstructionInfo> instructions = new ArrayList<>();
125 actionsInfos.add(new ActionNxResubmit(dispatcherTableId));
126 instructions.add(new InstructionApplyActions(actionsInfos));
130 public static List<MatchInfoBase> getCounterFlowMatch(ElementCountersRequest ecr, int lportTag,
131 ElementCountersDirection direction) {
132 List<MatchInfoBase> matches = new ArrayList<>();
133 if (ecr.isFilterExist(CountersUtils.ELEMENT_COUNTERS_IP_FILTER_GROUP_NAME, CountersUtils.IP_FILTER_NAME)) {
134 String ipFilter = ecr.getFilterFromFilterGroup(CountersUtils.ELEMENT_COUNTERS_IP_FILTER_GROUP_NAME,
135 CountersUtils.IP_FILTER_NAME);
136 matches.addAll(buildIpMatches(ipFilter, direction));
139 boolean tcpFilterExist = buildTcpMatchIfExists(ecr, matches);
141 if (!tcpFilterExist) {
142 buildUdpMatchIfExists(ecr, matches);
145 matches.add(CountersServiceUtils.buildLPortTagMatch(lportTag, direction));
150 public static Short getTableId(ElementCountersDirection direction) {
151 if (ElementCountersDirection.INGRESS.equals(direction)) {
152 return NwConstants.INGRESS_COUNTERS_TABLE;
153 } else if (ElementCountersDirection.EGRESS.equals(direction)) {
154 return NwConstants.EGRESS_COUNTERS_TABLE;
159 public static NodeRef buildNodeRef(BigInteger dpId) {
160 return new NodeRef(InstanceIdentifier.builder(Nodes.class)
161 .child(Node.class, new NodeKey(new NodeId(CountersUtils.OF_PREFIX + dpId))).build());
164 public static Flow createFlowOnTable(Match match, int priority, short tableId) {
165 return createFlowOnTable(match, priority, tableId, null, null);
168 public static Flow createFlowOnTable(Match match, int priority, short tableId, BigInteger cookie,
170 FlowBuilder fb = new FlowBuilder();
174 FlowId flowId = createFlowId();
175 fb.setTableId(tableId);
176 fb.setIdleTimeout(0).setHardTimeout(0);
178 if (timeout != null) {
179 fb.setHardTimeout(timeout);
181 if (cookie != null) {
182 fb.setCookie(new FlowCookie(cookie));
185 fb.setPriority(priority);
186 Flow flow = fb.build();
190 public static FlowId createFlowId() {
191 return getFlowIdUsingCounter();
194 private static FlowId getFlowIdUsingCounter() {
195 return new FlowId(String.valueOf(flowIdInc.incrementAndGet()));
198 private static boolean buildUdpMatchIfExists(ElementCountersRequest ecr, List<MatchInfoBase> matches) {
199 boolean udpFilterExist = false;
200 if (ecr.isFilterGroupExist(CountersUtils.ELEMENT_COUNTERS_UDP_FILTER_GROUP_NAME)) {
201 udpFilterExist = true;
202 matches.add(MatchIpProtocol.UDP);
204 if (ecr.isFilterExist(CountersUtils.ELEMENT_COUNTERS_UDP_FILTER_GROUP_NAME,
205 CountersUtils.UDP_SRC_PORT_FILTER_NAME)) {
207 Integer.valueOf(ecr.getFilterFromFilterGroup(CountersUtils.ELEMENT_COUNTERS_UDP_FILTER_GROUP_NAME,
208 CountersUtils.UDP_SRC_PORT_FILTER_NAME));
209 matches.add(new MatchUdpSourcePort(udpSrcPort));
211 if (ecr.isFilterExist(CountersUtils.ELEMENT_COUNTERS_UDP_FILTER_GROUP_NAME,
212 CountersUtils.UDP_DST_PORT_FILTER_NAME)) {
214 Integer.valueOf(ecr.getFilterFromFilterGroup(CountersUtils.ELEMENT_COUNTERS_UDP_FILTER_GROUP_NAME,
215 CountersUtils.UDP_DST_PORT_FILTER_NAME));
216 matches.add(new MatchUdpDestinationPort(udpDstPort));
219 return udpFilterExist;
222 private static boolean buildTcpMatchIfExists(ElementCountersRequest ecr, List<MatchInfoBase> matches) {
223 boolean tcpFilterExist = false;
224 if (ecr.isFilterGroupExist(CountersUtils.ELEMENT_COUNTERS_TCP_FILTER_GROUP_NAME)) {
225 tcpFilterExist = true;
226 matches.add(MatchIpProtocol.TCP);
228 if (ecr.isFilterExist(CountersUtils.ELEMENT_COUNTERS_TCP_FILTER_GROUP_NAME,
229 CountersUtils.TCP_SRC_PORT_FILTER_NAME)) {
230 int tcpSrcPort = Integer.parseInt(ecr.getFilterFromFilterGroup(
231 CountersUtils.ELEMENT_COUNTERS_TCP_FILTER_GROUP_NAME, CountersUtils.TCP_SRC_PORT_FILTER_NAME));
232 matches.add(new MatchTcpSourcePort(tcpSrcPort));
234 if (ecr.isFilterExist(CountersUtils.ELEMENT_COUNTERS_TCP_FILTER_GROUP_NAME,
235 CountersUtils.TCP_DST_PORT_FILTER_NAME)) {
236 int tcpDstPort = Integer.parseInt(ecr.getFilterFromFilterGroup(
237 CountersUtils.ELEMENT_COUNTERS_TCP_FILTER_GROUP_NAME, CountersUtils.TCP_DST_PORT_FILTER_NAME));
238 matches.add(new MatchTcpDestinationPort(tcpDstPort));
241 return tcpFilterExist;
244 private static List<MatchInfoBase> buildIpMatches(String ip, ElementCountersDirection direction) {
245 List<MatchInfoBase> flowMatches = new ArrayList<>();
246 IpAddress ipAddress = new IpAddress(ip.toCharArray());
247 if (ipAddress.getIpv4Address() != null) {
248 flowMatches.add(MatchEthernetType.IPV4);
249 flowMatches.add(direction == ElementCountersDirection.EGRESS
250 ? new MatchIpv4Source(ipAddress.getIpv4Address().getValue(), "32")
251 : new MatchIpv4Destination(ipAddress.getIpv4Address().getValue(), "32"));
253 flowMatches.add(MatchEthernetType.IPV6);
254 flowMatches.add(direction == ElementCountersDirection.EGRESS
255 ? new MatchIpv6Source(ipAddress.getIpv6Address().getValue() + "/128")
256 : new MatchIpv6Destination(ipAddress.getIpv6Address().getValue() + "/128"));