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