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