cc26575819fbd2bdcff614b8ca3270ba33afc12c
[onosfw.git] /
1 /*
2  * Copyright 2014-2015 Open Networking Laboratory
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  */
16 package org.onosproject.provider.of.flow.impl;
17
18 import com.google.common.collect.Lists;
19 import org.onlab.packet.Ip4Address;
20 import org.onlab.packet.Ip6Address;
21 import org.onosproject.net.OchSignal;
22 import org.onosproject.net.PortNumber;
23 import org.onosproject.net.flow.FlowRule;
24 import org.onosproject.net.flow.TrafficTreatment;
25 import org.onosproject.net.flow.instructions.Instruction;
26 import org.onosproject.net.flow.instructions.Instructions;
27 import org.onosproject.net.flow.instructions.Instructions.GroupInstruction;
28 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
29 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
30 import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
31 import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction;
32 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
33 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
34 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
35 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
36 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
37 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
38 import org.onosproject.net.flow.instructions.L2ModificationInstruction.PushHeaderInstructions;
39 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
40 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
41 import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
42 import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
43 import org.onosproject.net.flow.instructions.L4ModificationInstruction;
44 import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
45 import org.projectfloodlight.openflow.protocol.OFFactory;
46 import org.projectfloodlight.openflow.protocol.OFFlowAdd;
47 import org.projectfloodlight.openflow.protocol.OFFlowDelete;
48 import org.projectfloodlight.openflow.protocol.OFFlowMod;
49 import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
50 import org.projectfloodlight.openflow.protocol.action.OFAction;
51 import org.projectfloodlight.openflow.protocol.action.OFActionGroup;
52 import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
53 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
54 import org.projectfloodlight.openflow.protocol.match.Match;
55 import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
56 import org.projectfloodlight.openflow.types.CircuitSignalID;
57 import org.projectfloodlight.openflow.types.EthType;
58 import org.projectfloodlight.openflow.types.IPv4Address;
59 import org.projectfloodlight.openflow.types.IPv6Address;
60 import org.projectfloodlight.openflow.types.IPv6FlowLabel;
61 import org.projectfloodlight.openflow.types.MacAddress;
62 import org.projectfloodlight.openflow.types.OFBooleanValue;
63 import org.projectfloodlight.openflow.types.OFBufferId;
64 import org.projectfloodlight.openflow.types.OFGroup;
65 import org.projectfloodlight.openflow.types.OFPort;
66 import org.projectfloodlight.openflow.types.OFVlanVidMatch;
67 import org.projectfloodlight.openflow.types.TableId;
68 import org.projectfloodlight.openflow.types.TransportPort;
69 import org.projectfloodlight.openflow.types.U32;
70 import org.projectfloodlight.openflow.types.U64;
71 import org.projectfloodlight.openflow.types.VlanPcp;
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
74
75 import java.util.Collections;
76 import java.util.LinkedList;
77 import java.util.List;
78 import java.util.Optional;
79
80 /**
81  * Flow mod builder for OpenFlow 1.3+.
82  */
83 public class FlowModBuilderVer13 extends FlowModBuilder {
84
85     private final Logger log = LoggerFactory.getLogger(getClass());
86     private static final int OFPCML_NO_BUFFER = 0xffff;
87
88     private final TrafficTreatment treatment;
89
90     /**
91      * Constructor for a flow mod builder for OpenFlow 1.3.
92      *
93      * @param flowRule the flow rule to transform into a flow mod
94      * @param factory the OpenFlow factory to use to build the flow mod
95      * @param xid the transaction ID
96      */
97     protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional<Long> xid) {
98         super(flowRule, factory, xid);
99
100         this.treatment = flowRule.treatment();
101     }
102
103     @Override
104     public OFFlowAdd buildFlowAdd() {
105         Match match = buildMatch();
106         List<OFAction> deferredActions = buildActions(treatment.deferred());
107         List<OFAction> immediateActions = buildActions(treatment.immediate());
108         List<OFInstruction> instructions = Lists.newLinkedList();
109
110
111         if (treatment.clearedDeferred()) {
112             instructions.add(factory().instructions().clearActions());
113         }
114         if (immediateActions.size() > 0) {
115             instructions.add(factory().instructions().applyActions(immediateActions));
116         }
117         if (deferredActions.size() > 0) {
118             instructions.add(factory().instructions().writeActions(deferredActions));
119         }
120         if (treatment.tableTransition() != null) {
121             instructions.add(buildTableGoto(treatment.tableTransition()));
122         }
123         if (treatment.writeMetadata() != null) {
124             instructions.add(buildMetadata(treatment.writeMetadata()));
125         }
126         if (treatment.metered() != null) {
127             instructions.add(buildMeter(treatment.metered()));
128         }
129
130         long cookie = flowRule().id().value();
131
132         OFFlowAdd fm = factory().buildFlowAdd()
133                 .setXid(xid)
134                 .setCookie(U64.of(cookie))
135                 .setBufferId(OFBufferId.NO_BUFFER)
136                 .setInstructions(instructions)
137                 .setMatch(match)
138                 .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
139                 .setPriority(flowRule().priority())
140                 .setTableId(TableId.of(flowRule().tableId()))
141                 .build();
142
143         return fm;
144     }
145
146     @Override
147     public OFFlowMod buildFlowMod() {
148         Match match = buildMatch();
149         List<OFAction> deferredActions = buildActions(treatment.deferred());
150         List<OFAction> immediateActions = buildActions(treatment.immediate());
151         List<OFInstruction> instructions = Lists.newLinkedList();
152
153
154         if (immediateActions.size() > 0) {
155             instructions.add(factory().instructions().applyActions(immediateActions));
156         }
157         if (treatment.clearedDeferred()) {
158             instructions.add(factory().instructions().clearActions());
159         }
160         if (deferredActions.size() > 0) {
161             instructions.add(factory().instructions().writeActions(deferredActions));
162         }
163         if (treatment.tableTransition() != null) {
164             instructions.add(buildTableGoto(treatment.tableTransition()));
165         }
166         if (treatment.writeMetadata() != null) {
167             instructions.add(buildMetadata(treatment.writeMetadata()));
168         }
169         if (treatment.metered() != null) {
170             instructions.add(buildMeter(treatment.metered()));
171         }
172
173         long cookie = flowRule().id().value();
174
175         OFFlowMod fm = factory().buildFlowModify()
176                 .setXid(xid)
177                 .setCookie(U64.of(cookie))
178                 .setBufferId(OFBufferId.NO_BUFFER)
179                 .setInstructions(instructions)
180                 .setMatch(match)
181                 .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
182                 .setPriority(flowRule().priority())
183                 .setTableId(TableId.of(flowRule().tableId()))
184                 .build();
185
186         return fm;
187     }
188
189     @Override
190     public OFFlowDelete buildFlowDel() {
191         Match match = buildMatch();
192
193         long cookie = flowRule().id().value();
194
195         OFFlowDelete fm = factory().buildFlowDelete()
196                 .setXid(xid)
197                 .setCookie(U64.of(cookie))
198                 .setBufferId(OFBufferId.NO_BUFFER)
199                 .setMatch(match)
200                 .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
201                 .setPriority(flowRule().priority())
202                 .setTableId(TableId.of(flowRule().tableId()))
203                 .build();
204
205         return fm;
206     }
207
208     private List<OFAction> buildActions(List<Instruction> treatments) {
209         if (treatment == null) {
210             return Collections.emptyList();
211         }
212
213         boolean tableFound = false;
214         List<OFAction> actions = new LinkedList<>();
215         for (Instruction i : treatments) {
216             switch (i.type()) {
217                 case DROP:
218                 case NOACTION:
219                     return Collections.emptyList();
220                 case L0MODIFICATION:
221                     actions.add(buildL0Modification(i));
222                     break;
223                 case L2MODIFICATION:
224                     actions.add(buildL2Modification(i));
225                     break;
226                 case L3MODIFICATION:
227                     actions.add(buildL3Modification(i));
228                     break;
229                 case L4MODIFICATION:
230                     actions.add(buildL4Modification(i));
231                     break;
232                 case OUTPUT:
233                     OutputInstruction out = (OutputInstruction) i;
234                     OFActionOutput.Builder action = factory().actions().buildOutput()
235                             .setPort(OFPort.of((int) out.port().toLong()));
236                     if (out.port().equals(PortNumber.CONTROLLER)) {
237                         action.setMaxLen(OFPCML_NO_BUFFER);
238                     }
239                     actions.add(action.build());
240                     break;
241                 case GROUP:
242                     GroupInstruction group = (GroupInstruction) i;
243                     OFActionGroup.Builder groupBuilder = factory().actions().buildGroup()
244                             .setGroup(OFGroup.of(group.groupId().id()));
245                     actions.add(groupBuilder.build());
246                     break;
247                 case TABLE:
248                     //FIXME: should not occur here.
249                     tableFound = true;
250                     break;
251                 default:
252                     log.warn("Instruction type {} not yet implemented.", i.type());
253             }
254         }
255         if (tableFound && actions.isEmpty()) {
256             // handles the case where there are no actions, but there is
257             // a goto instruction for the next table
258             return Collections.emptyList();
259         }
260         return actions;
261     }
262
263     private OFInstruction buildTableGoto(Instructions.TableTypeTransition i) {
264         OFInstruction instruction = factory().instructions().gotoTable(
265                 TableId.of(i.tableId()));
266         return instruction;
267     }
268
269     private OFInstruction buildMetadata(Instructions.MetadataInstruction m) {
270         OFInstruction instruction = factory().instructions().writeMetadata(
271                 U64.of(m.metadata()), U64.of(m.metadataMask()));
272         return instruction;
273     }
274
275     private OFInstruction buildMeter(Instructions.MeterInstruction metered) {
276         return factory().instructions().meter(metered.meterId().id());
277     }
278
279
280     private OFAction buildL0Modification(Instruction i) {
281         L0ModificationInstruction l0m = (L0ModificationInstruction) i;
282         switch (l0m.subtype()) {
283             case LAMBDA:
284                 return buildModLambdaInstruction((ModLambdaInstruction) i);
285             case OCH:
286                 try {
287                     return buildModOchSignalInstruction((ModOchSignalInstruction) i);
288                 } catch (NoMappingFoundException e) {
289                     log.warn(e.getMessage());
290                     break;
291                 }
292             default:
293                 log.warn("Unimplemented action type {}.", l0m.subtype());
294                 break;
295         }
296         return null;
297     }
298
299     private OFAction buildModLambdaInstruction(ModLambdaInstruction instruction) {
300         return factory().actions().circuit(factory().oxms().ochSigidBasic(
301                 new CircuitSignalID((byte) 1, (byte) 2, instruction.lambda(), (short) 1)));
302     }
303
304     private OFAction buildModOchSignalInstruction(ModOchSignalInstruction instruction) {
305         OchSignal signal = instruction.lambda();
306         byte gridType = OpenFlowValueMapper.lookupGridType(signal.gridType());
307         byte channelSpacing = OpenFlowValueMapper.lookupChannelSpacing(signal.channelSpacing());
308
309         return factory().actions().circuit(factory().oxms().ochSigidBasic(
310                 new CircuitSignalID(gridType, channelSpacing,
311                         (short) signal.spacingMultiplier(), (short) signal.slotGranularity())
312         ));
313     }
314
315     private OFAction buildL2Modification(Instruction i) {
316         L2ModificationInstruction l2m = (L2ModificationInstruction) i;
317         ModEtherInstruction eth;
318         OFOxm<?> oxm = null;
319         switch (l2m.subtype()) {
320             case ETH_DST:
321                 eth = (ModEtherInstruction) l2m;
322                 oxm = factory().oxms().ethDst(MacAddress.of(eth.mac().toLong()));
323                 break;
324             case ETH_SRC:
325                 eth = (ModEtherInstruction) l2m;
326                 oxm = factory().oxms().ethSrc(MacAddress.of(eth.mac().toLong()));
327                 break;
328             case VLAN_ID:
329                 ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m;
330                 oxm = factory().oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanId.vlanId().toShort()));
331                 break;
332             case VLAN_PCP:
333                 ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m;
334                 oxm = factory().oxms().vlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
335                 break;
336             case MPLS_PUSH:
337                 PushHeaderInstructions pushHeaderInstructions =
338                         (PushHeaderInstructions) l2m;
339                 return factory().actions().pushMpls(EthType.of(pushHeaderInstructions
340                                                                .ethernetType().toShort()));
341             case MPLS_POP:
342                 PushHeaderInstructions popHeaderInstructions =
343                         (PushHeaderInstructions) l2m;
344                 return factory().actions().popMpls(EthType.of(popHeaderInstructions
345                                                               .ethernetType().toShort()));
346             case MPLS_LABEL:
347                 ModMplsLabelInstruction mplsLabel =
348                         (ModMplsLabelInstruction) l2m;
349                 oxm = factory().oxms().mplsLabel(U32.of(mplsLabel.mplsLabel().toInt()));
350                 break;
351             case MPLS_BOS:
352                 ModMplsBosInstruction mplsBos = (ModMplsBosInstruction) l2m;
353                 oxm = factory().oxms()
354                         .mplsBos(mplsBos.mplsBos() ? OFBooleanValue.TRUE
355                                                    : OFBooleanValue.FALSE);
356                 break;
357             case DEC_MPLS_TTL:
358                 return factory().actions().decMplsTtl();
359             case VLAN_POP:
360                 return factory().actions().popVlan();
361             case VLAN_PUSH:
362                 PushHeaderInstructions pushVlanInstruction = (PushHeaderInstructions) l2m;
363                 return factory().actions().pushVlan(
364                         EthType.of(pushVlanInstruction.ethernetType().toShort()));
365             case TUNNEL_ID:
366                 ModTunnelIdInstruction tunnelId = (ModTunnelIdInstruction) l2m;
367                 oxm = factory().oxms().tunnelId(U64.of(tunnelId.tunnelId()));
368                 break;
369             default:
370                 log.warn("Unimplemented action type {}.", l2m.subtype());
371                 break;
372         }
373
374         if (oxm != null) {
375             return factory().actions().buildSetField().setField(oxm).build();
376         }
377         return null;
378     }
379
380     private OFAction buildL3Modification(Instruction i) {
381         L3ModificationInstruction l3m = (L3ModificationInstruction) i;
382         ModIPInstruction ip;
383         Ip4Address ip4;
384         Ip6Address ip6;
385         OFOxm<?> oxm = null;
386         switch (l3m.subtype()) {
387             case IPV4_SRC:
388                 ip = (ModIPInstruction) i;
389                 ip4 = ip.ip().getIp4Address();
390                 oxm = factory().oxms().ipv4Src(IPv4Address.of(ip4.toInt()));
391                 break;
392             case IPV4_DST:
393                 ip = (ModIPInstruction) i;
394                 ip4 = ip.ip().getIp4Address();
395                 oxm = factory().oxms().ipv4Dst(IPv4Address.of(ip4.toInt()));
396                 break;
397             case IPV6_SRC:
398                 ip = (ModIPInstruction) i;
399                 ip6 = ip.ip().getIp6Address();
400                 oxm = factory().oxms().ipv6Src(IPv6Address.of(ip6.toOctets()));
401                 break;
402             case IPV6_DST:
403                 ip = (ModIPInstruction) i;
404                 ip6 = ip.ip().getIp6Address();
405                 oxm = factory().oxms().ipv6Dst(IPv6Address.of(ip6.toOctets()));
406                 break;
407             case IPV6_FLABEL:
408                 ModIPv6FlowLabelInstruction flowLabelInstruction =
409                         (ModIPv6FlowLabelInstruction) i;
410                 int flowLabel = flowLabelInstruction.flowLabel();
411                 oxm = factory().oxms().ipv6Flabel(IPv6FlowLabel.of(flowLabel));
412                 break;
413             case DEC_TTL:
414                 return factory().actions().decNwTtl();
415             case TTL_IN:
416                 return factory().actions().copyTtlIn();
417             case TTL_OUT:
418                 return factory().actions().copyTtlOut();
419             default:
420                 log.warn("Unimplemented action type {}.", l3m.subtype());
421                 break;
422         }
423
424         if (oxm != null) {
425             return factory().actions().buildSetField().setField(oxm).build();
426         }
427         return null;
428     }
429
430     private OFAction buildL4Modification(Instruction i) {
431         L4ModificationInstruction l4m = (L4ModificationInstruction) i;
432         ModTransportPortInstruction tp;
433         OFOxm<?> oxm = null;
434         switch (l4m.subtype()) {
435             case TCP_SRC:
436                 tp = (ModTransportPortInstruction) l4m;
437                 oxm = factory().oxms().tcpSrc(TransportPort.of(tp.port().toInt()));
438                 break;
439             case TCP_DST:
440                 tp = (ModTransportPortInstruction) l4m;
441                 oxm = factory().oxms().tcpDst(TransportPort.of(tp.port().toInt()));
442                 break;
443             case UDP_SRC:
444                 tp = (ModTransportPortInstruction) l4m;
445                 oxm = factory().oxms().udpSrc(TransportPort.of(tp.port().toInt()));
446                 break;
447             case UDP_DST:
448                 tp = (ModTransportPortInstruction) l4m;
449                 oxm = factory().oxms().udpDst(TransportPort.of(tp.port().toInt()));
450                 break;
451             default:
452                 log.warn("Unimplemented action type {}.", l4m.subtype());
453                 break;
454         }
455
456         if (oxm != null) {
457             return factory().actions().buildSetField().setField(oxm).build();
458         }
459         return null;
460     }
461
462 }