2 * Copyright © 2017 Ericsson, 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.netvirt.sfc.classifier.providers;
11 import com.google.common.net.InetAddresses;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.List;
15 import javax.inject.Singleton;
16 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.genius.mdsalutil.NwConstants;
19 import org.opendaylight.netvirt.sfc.classifier.utils.AclMatches;
20 import org.opendaylight.netvirt.sfc.classifier.utils.OpenFlow13Utils;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
33 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 public class OpenFlow13Provider {
37 // Unique cookie values for each type of flow
38 public static final BigInteger INGRESS_CLASSIFIER_FILTER_COOKIE = new BigInteger("F005BA1100000001", 16);
39 public static final BigInteger INGRESS_CLASSIFIER_ACL_COOKIE = new BigInteger("F005BA1100000002", 16);
40 public static final BigInteger EGRESS_CLASSIFIER_FILTER_COOKIE = new BigInteger("F005BA1100000003", 16);
41 public static final BigInteger EGRESS_CLASSIFIER_NEXTHOP_COOKIE = new BigInteger("F005BA1100000004", 16);
42 public static final BigInteger EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE = new BigInteger("F005BA1100000005", 16);
43 public static final int SFC_SERVICE_PRIORITY = 6;
45 // Priorities for each flow
46 public static final int INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY = 510;
47 public static final int INGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY = 500;
48 public static final int INGRESS_CLASSIFIER_ACL_PRIORITY = 500;
49 public static final int EGRESS_CLASSIFIER_FILTER_NSH_PRIORITY = 260;
50 public static final int EGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY = 250;
51 public static final int EGRESS_CLASSIFIER_NEXTHOP_C1C2_PRIORITY = 250;
52 public static final int EGRESS_CLASSIFIER_NEXTHOP_NOC1C2_PRIORITY = 260;
53 public static final int EGRESS_CLASSIFIER_EGRESS_LOCAL_PRIORITY = 260;
54 public static final int EGRESS_CLASSIFIER_EGRESS_REMOTE_PRIORITY = 250;
56 // Flow names for each table
57 public static final String INGRESS_CLASSIFIER_FILTER_VXGPENSH_FLOW_NAME = "nvsfc_ingr_class_filter_vxgpe";
58 public static final String INGRESS_CLASSIFIER_FILTER_ETHNSH_FLOW_NAME = "nvsfc_ingr_class_filter_eth";
59 public static final String INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME = "nvsfc_ingr_class_filter_nonsh";
60 public static final String INGRESS_CLASSIFIER_ACL_FLOW_NAME = "nvsfc_ingr_class_acl";
61 public static final String EGRESS_CLASSIFIER_FILTER_VXGPENSH_FLOW_NAME = "nvsfc_egr_class_filter_vxgpe";
62 public static final String EGRESS_CLASSIFIER_FILTER_ETHNSH_FLOW_NAME = "nvsfc_egr_class_filter_eth";
63 public static final String EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME = "nvsfc_egr_class_filter_nonsh";
64 public static final String EGRESS_CLASSIFIER_NEXTHOP_C1C2_FLOW_NAME = "nvsfc_egr_class_nexthop_c1c2";
65 public static final String EGRESS_CLASSIFIER_NEXTHOP_NOC1C2_FLOW_NAME = "nvsfc_egr_class_nexthop_noc1c2";
66 public static final String EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME = "nvsfc_egr_class_ tport egress";
68 public static final short NSH_MDTYPE_ONE = 0x01;
69 public static final long DEFAULT_NSH_CONTEXT_VALUE = 0L;
70 private static final int DEFAULT_NETMASK = 32;
72 public MatchBuilder getMatchBuilderFromAceMatches(Matches matches) {
73 if (matches == null) {
77 return new AclMatches(matches).buildMatch();
80 public void appendFlowForCreate(NodeId node, Flow flow, WriteTransaction tx) {
81 NodeKey nodeKey = new NodeKey(node);
82 InstanceIdentifier<Flow> iidFlow = InstanceIdentifier.builder(Nodes.class)
83 .child(Node.class, nodeKey)
84 .augmentation(FlowCapableNode.class)
85 .child(Table.class, new TableKey(flow.getTableId()))
86 .child(Flow.class, flow.getKey())
89 tx.put(LogicalDatastoreType.CONFIGURATION, iidFlow, flow, true);
92 public void appendFlowForDelete(NodeId node, Flow flow, WriteTransaction tx) {
93 NodeKey nodeKey = new NodeKey(node);
94 InstanceIdentifier<Flow> iidFlow = InstanceIdentifier.builder(Nodes.class)
95 .child(Node.class, nodeKey)
96 .augmentation(FlowCapableNode.class)
97 .child(Table.class, new TableKey(flow.getTableId()))
98 .child(Flow.class, flow.getKey())
101 tx.delete(LogicalDatastoreType.CONFIGURATION, iidFlow);
105 * Ingress Classifier Filter Vxgpe NSH flow:
106 * Only allows Non-NSH packets to proceed in the classifier
107 * Match on NSP and resubmit to Ingress Dispatch on match
109 public Flow createIngressClassifierFilterVxgpeNshFlow(NodeId nodeId) {
110 MatchBuilder match = new MatchBuilder();
111 OpenFlow13Utils.addMatchVxgpeNsh(match);
113 List<Action> actionList = new ArrayList<>();
114 actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE,
117 InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
118 String flowIdStr = INGRESS_CLASSIFIER_FILTER_VXGPENSH_FLOW_NAME + nodeId.getValue();
120 return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
121 INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
122 INGRESS_CLASSIFIER_FILTER_VXGPENSH_FLOW_NAME, flowIdStr, match, isb).build();
126 * Ingress Classifier Filter Eth NSH flow:
127 * Only allows Non-NSH packets to proceed in the classifier
128 * Match on NSP and resubmit to Ingress Dispatch on match
130 public Flow createIngressClassifierFilterEthNshFlow(NodeId nodeId) {
131 MatchBuilder match = new MatchBuilder();
132 OpenFlow13Utils.addMatchEthNsh(match);
134 List<Action> actionList = new ArrayList<>();
135 actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE,
138 InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
139 String flowIdStr = INGRESS_CLASSIFIER_FILTER_ETHNSH_FLOW_NAME + nodeId.getValue();
141 return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
142 INGRESS_CLASSIFIER_FILTER_NSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
143 INGRESS_CLASSIFIER_FILTER_ETHNSH_FLOW_NAME, flowIdStr, match, isb).build();
147 * Ingress Classifier Filter No NSH flow:
148 * Only allows Non-NSH packets to proceed in the classifier
149 * Match Any (NSH not present), Goto Classifier ACL table
151 public Flow createIngressClassifierFilterNoNshFlow(NodeId nodeId) {
153 MatchBuilder match = new MatchBuilder();
155 InstructionsBuilder isb = OpenFlow13Utils.appendGotoTableInstruction(new InstructionsBuilder(),
156 NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE);
157 String flowIdStr = INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME + nodeId.getValue();
159 return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_FILTER_TABLE,
160 INGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY, INGRESS_CLASSIFIER_FILTER_COOKIE,
161 INGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME, flowIdStr, match, isb).build();
165 * Ingress Classifier ACL flow:
166 * Performs the ACL classification, and sends packets to Ingress Dispatcher
167 * Match on inport (corresponds to Neutron NW/tenant), Push NSH, init(nsp, nsi, C1, C2),
168 * set SFFIp in Reg0, and resubmit to Ingress Dispatcher to be sent down the rest of
171 public Flow createIngressClassifierAclFlow(NodeId nodeId, MatchBuilder match, Long port, String sffIpStr,
172 long nsp, short nsi) {
173 OpenFlow13Utils.addMatchInPort(match, nodeId, port);
175 Long ipl = InetAddresses.coerceToInteger(InetAddresses.forString(sffIpStr)) & 0xffffffffL;
176 List<Action> actionList = new ArrayList<>();
177 actionList.add(OpenFlow13Utils.createActionNxPushNsh(actionList.size()));
178 actionList.add(OpenFlow13Utils.createActionNxLoadNshMdtype(NSH_MDTYPE_ONE, actionList.size()));
179 actionList.add(OpenFlow13Utils.createActionNxLoadNsp((int) nsp, actionList.size()));
180 actionList.add(OpenFlow13Utils.createActionNxLoadNsi(nsi, actionList.size()));
181 actionList.add(OpenFlow13Utils.createActionNxLoadNshc1(DEFAULT_NSH_CONTEXT_VALUE, actionList.size()));
182 actionList.add(OpenFlow13Utils.createActionNxLoadNshc2(DEFAULT_NSH_CONTEXT_VALUE, actionList.size()));
183 actionList.add(OpenFlow13Utils.createActionNxLoadReg0(ipl, actionList.size()));
184 actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.LPORT_DISPATCHER_TABLE,
187 InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
189 // The flowIdStr needs to be unique, so the best way to make it unique is to use the match
190 String flowIdStr = INGRESS_CLASSIFIER_ACL_FLOW_NAME + "_" + nodeId.getValue() + match.build().toString();
192 return OpenFlow13Utils.createFlowBuilder(NwConstants.INGRESS_SFC_CLASSIFIER_ACL_TABLE,
193 INGRESS_CLASSIFIER_ACL_PRIORITY, INGRESS_CLASSIFIER_ACL_COOKIE, INGRESS_CLASSIFIER_ACL_FLOW_NAME,
194 flowIdStr, match, isb).build();
199 // Internal EgressFlow util methods
203 * Egress Classifier Filter Vxgpe NSH flow:
204 * Only allows NSH packets to proceed in the egress classifier
205 * Match on NSP, Goto table Egress Classifier NextHop on match
207 public Flow createEgressClassifierFilterVxgpeNshFlow(NodeId nodeId) {
208 MatchBuilder match = new MatchBuilder();
209 OpenFlow13Utils.addMatchVxgpeNsh(match);
211 InstructionsBuilder isb = OpenFlow13Utils.appendGotoTableInstruction(new InstructionsBuilder(),
212 NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE);
213 String flowIdStr = EGRESS_CLASSIFIER_FILTER_VXGPENSH_FLOW_NAME + nodeId.getValue();
215 return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE,
216 EGRESS_CLASSIFIER_FILTER_NSH_PRIORITY, EGRESS_CLASSIFIER_FILTER_COOKIE,
217 EGRESS_CLASSIFIER_FILTER_VXGPENSH_FLOW_NAME, flowIdStr, match, isb).build();
221 * Egress Classifier Filter Eth NSH flow:
222 * Only allows NSH packets to proceed in the egress classifier
223 * Match on NSP, Goto table Egress Classifier NextHop on match
225 public Flow createEgressClassifierFilterEthNshFlow(NodeId nodeId) {
226 MatchBuilder match = new MatchBuilder();
227 OpenFlow13Utils.addMatchEthNsh(match);
229 InstructionsBuilder isb = OpenFlow13Utils.appendGotoTableInstruction(new InstructionsBuilder(),
230 NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE);
231 String flowIdStr = EGRESS_CLASSIFIER_FILTER_ETHNSH_FLOW_NAME + nodeId.getValue();
233 return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE,
234 EGRESS_CLASSIFIER_FILTER_NSH_PRIORITY, EGRESS_CLASSIFIER_FILTER_COOKIE,
235 EGRESS_CLASSIFIER_FILTER_ETHNSH_FLOW_NAME, flowIdStr, match, isb).build();
239 * Egress Classifier Filter No NSH flow:
240 * Only allows NSH packets to proceed in the egress classifier
241 * MatchAny (NSH not present), Resubmit to Egress Dispatcher
242 * since the packet is not for SFC
244 public Flow createEgressClassifierFilterNoNshFlow(NodeId nodeId) {
245 MatchBuilder match = new MatchBuilder();
247 List<Action> actionList = new ArrayList<>();
248 actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE,
251 InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
252 String flowIdStr = EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME + nodeId.getValue();
254 return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_FILTER_TABLE,
255 EGRESS_CLASSIFIER_FILTER_NONSH_PRIORITY, EGRESS_CLASSIFIER_FILTER_COOKIE,
256 EGRESS_CLASSIFIER_FILTER_NONSH_FLOW_NAME, flowIdStr, match, isb).build();
260 * Egress Classifier NextHop No C1/C2 flow:
261 * Set C1/C2 accordingly
262 * Match [C1, C2] == [0, 0], Move [TunIpv4Dst, TunVnid] to [C1, C2],
263 * Move Reg0 (SFF IP) to TunIpv4Dst, and goto Egress Classifier
264 * Transport Egress table on match
266 public Flow createEgressClassifierNextHopNoC1C2Flow(NodeId nodeId) {
267 MatchBuilder match = new MatchBuilder();
268 OpenFlow13Utils.addMatchNshNsc1(match, DEFAULT_NSH_CONTEXT_VALUE);
269 OpenFlow13Utils.addMatchNshNsc2(match, DEFAULT_NSH_CONTEXT_VALUE);
271 List<Action> actionList = new ArrayList<>();
272 actionList.add(OpenFlow13Utils.createActionNxMoveTunIpv4DstToNsc1Register(actionList.size()));
273 actionList.add(OpenFlow13Utils.createActionNxMoveTunIdToNsc2Register(actionList.size()));
274 actionList.add(OpenFlow13Utils.createActionNxMoveReg0ToTunIpv4Dst(actionList.size()));
276 InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
277 OpenFlow13Utils.appendGotoTableInstruction(isb, NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE);
278 String flowIdStr = EGRESS_CLASSIFIER_NEXTHOP_NOC1C2_FLOW_NAME + nodeId.getValue();
280 return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE,
281 EGRESS_CLASSIFIER_NEXTHOP_NOC1C2_PRIORITY, EGRESS_CLASSIFIER_NEXTHOP_COOKIE,
282 EGRESS_CLASSIFIER_NEXTHOP_NOC1C2_FLOW_NAME, flowIdStr, match, isb).build();
286 * Egress Classifier NextHop with C1/C2 flow:
287 * Set C1/C2 accordingly
288 * MatchAny (C1, C2 already set) goto Egress Classifier
289 * Transport Egress table
291 public Flow createEgressClassifierNextHopC1C2Flow(NodeId nodeId) {
292 MatchBuilder match = new MatchBuilder();
294 InstructionsBuilder isb = OpenFlow13Utils.appendGotoTableInstruction(new InstructionsBuilder(),
295 NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE);
296 String flowIdStr = EGRESS_CLASSIFIER_NEXTHOP_C1C2_FLOW_NAME + nodeId.getValue();
298 return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_NEXTHOP_TABLE,
299 EGRESS_CLASSIFIER_NEXTHOP_C1C2_PRIORITY, EGRESS_CLASSIFIER_NEXTHOP_COOKIE,
300 EGRESS_CLASSIFIER_NEXTHOP_C1C2_FLOW_NAME, flowIdStr, match, isb).build();
304 * Egress Classifier TransportEgress Local Flow
305 * Final egress processing and egress packets. Determines if the
306 * packet should go to a local or remote SFF.
307 * Match on [Nsp, TunIpv4Dst==thisNodeIp], Resubmit to Ingress
308 * Dispatcher to be processed by SFC SFF on match
310 public Flow createEgressClassifierTransportEgressLocalFlow(NodeId nodeId, long nsp, String localIpStr) {
311 MatchBuilder match = OpenFlow13Utils.getNspMatch(nsp);
312 OpenFlow13Utils.addMatchTunIpv4Dst(match, localIpStr, DEFAULT_NETMASK);
314 List<Action> actionList = new ArrayList<>();
315 actionList.add(OpenFlow13Utils.createActionResubmitTable(NwConstants.SFC_TRANSPORT_INGRESS_TABLE,
318 InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
319 String flowIdStr = EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp + "_" + localIpStr;
321 return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE,
322 EGRESS_CLASSIFIER_EGRESS_LOCAL_PRIORITY, EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE,
323 EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME, flowIdStr, match, isb).build();
327 * Egress Classifier TransportEgress Remote Flow
328 * Final egress processing and egress packets. Determines if the
329 * packet should go to a local or remote SFF.
330 * Match on Nsp, Output to port to send to remote SFF on match.
332 public Flow createEgressClassifierTransportEgressRemoteFlow(NodeId nodeId, long nsp, long outport) {
333 MatchBuilder match = OpenFlow13Utils.getNspMatch(nsp);
335 List<Action> actionList = new ArrayList<>();
336 actionList.add(OpenFlow13Utils.createActionOutPort("output:" + outport, actionList.size()));
338 InstructionsBuilder isb = OpenFlow13Utils.wrapActionsIntoApplyActionsInstruction(actionList);
339 String flowIdStr = EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME + nodeId.getValue() + "_" + nsp;
341 return OpenFlow13Utils.createFlowBuilder(NwConstants.EGRESS_SFC_CLASSIFIER_EGRESS_TABLE,
342 EGRESS_CLASSIFIER_EGRESS_REMOTE_PRIORITY, EGRESS_CLASSIFIER_TPORTEGRESS_COOKIE,
343 EGRESS_CLASSIFIER_TPORTEGRESS_FLOW_NAME, flowIdStr, match, isb).build();