c91616df480665fa0f8e38c5b7a2748b7bf24b65
[onosfw.git] /
1 /*
2  * Copyright 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.group.impl;
17
18 import static org.slf4j.LoggerFactory.getLogger;
19
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.LinkedList;
23 import java.util.List;
24 import java.util.Optional;
25
26 import org.onlab.packet.Ip4Address;
27 import org.onlab.packet.Ip6Address;
28 import org.onosproject.core.GroupId;
29 import org.onosproject.net.DeviceId;
30 import org.onosproject.net.PortNumber;
31 import org.onosproject.net.driver.DefaultDriverData;
32 import org.onosproject.net.driver.DefaultDriverHandler;
33 import org.onosproject.net.driver.Driver;
34 import org.onosproject.net.driver.DriverService;
35 import org.onosproject.net.flow.TrafficTreatment;
36 import org.onosproject.net.flow.instructions.ExtensionInstruction;
37 import org.onosproject.net.flow.instructions.Instruction;
38 import org.onosproject.net.flow.instructions.Instructions;
39 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
40 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
41 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
42 import org.onosproject.net.group.GroupBucket;
43 import org.onosproject.net.group.GroupBuckets;
44 import org.onosproject.net.group.GroupDescription;
45 import org.onosproject.openflow.controller.ExtensionInterpreter;
46 import org.projectfloodlight.openflow.protocol.OFBucket;
47 import org.projectfloodlight.openflow.protocol.OFFactory;
48 import org.projectfloodlight.openflow.protocol.OFGroupAdd;
49 import org.projectfloodlight.openflow.protocol.OFGroupDelete;
50 import org.projectfloodlight.openflow.protocol.OFGroupMod;
51 import org.projectfloodlight.openflow.protocol.OFGroupType;
52 import org.projectfloodlight.openflow.protocol.action.OFAction;
53 import org.projectfloodlight.openflow.protocol.action.OFActionGroup;
54 import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
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.OFGroup;
64 import org.projectfloodlight.openflow.types.OFPort;
65 import org.projectfloodlight.openflow.types.OFVlanVidMatch;
66 import org.projectfloodlight.openflow.types.U32;
67 import org.projectfloodlight.openflow.types.VlanPcp;
68 import org.slf4j.Logger;
69
70 /*
71  * Builder for GroupMod.
72  */
73 public final class GroupModBuilder {
74
75     private GroupBuckets buckets;
76     private GroupId groupId;
77     private GroupDescription.Type type;
78     private OFFactory factory;
79     private Long xid;
80     private Optional<DriverService> driverService;
81
82     private final Logger log = getLogger(getClass());
83
84     private static final int OFPCML_NO_BUFFER = 0xffff;
85
86     private GroupModBuilder(GroupBuckets buckets, GroupId groupId,
87                              GroupDescription.Type type, OFFactory factory,
88                              Optional<Long> xid) {
89         this.buckets = buckets;
90         this.groupId = groupId;
91         this.type = type;
92         this.factory = factory;
93         this.xid = xid.orElse((long) 0);
94     }
95
96     private GroupModBuilder(GroupBuckets buckets, GroupId groupId,
97                             GroupDescription.Type type, OFFactory factory,
98                             Optional<Long> xid, Optional<DriverService> driverService) {
99        this.buckets = buckets;
100        this.groupId = groupId;
101        this.type = type;
102        this.factory = factory;
103        this.xid = xid.orElse((long) 0);
104        this.driverService = driverService;
105    }
106     /**
107      * Creates a builder for GroupMod.
108      *
109      * @param buckets GroupBuckets object
110      * @param groupId Group Id to create
111      * @param type Group type
112      * @param factory OFFactory object
113      * @param xid transaction ID
114      * @return GroupModBuilder object
115      */
116     public static GroupModBuilder builder(GroupBuckets buckets, GroupId groupId,
117                                           GroupDescription.Type type, OFFactory factory,
118                                           Optional<Long> xid) {
119
120         return new GroupModBuilder(buckets, groupId, type, factory, xid);
121     }
122
123     /**
124      * Creates a builder for GroupMod.
125      *
126      * @param buckets GroupBuckets object
127      * @param groupId Group Id to create
128      * @param type Group type
129      * @param factory OFFactory object
130      * @param xid transaction ID
131      * @param driverService driver Service
132      * @return GroupModBuilder object
133      */
134     public static GroupModBuilder builder(GroupBuckets buckets, GroupId groupId,
135                                           GroupDescription.Type type, OFFactory factory,
136                                           Optional<Long> xid, Optional<DriverService> driverService) {
137
138         return new GroupModBuilder(buckets, groupId, type, factory, xid, driverService);
139     }
140
141     /**
142      * Builds the GroupAdd OF message.
143      *
144      * @return GroupAdd OF message
145      */
146     public OFGroupAdd buildGroupAdd() {
147
148         List<OFBucket> ofBuckets = new ArrayList<OFBucket>();
149         for (GroupBucket bucket: buckets.buckets()) {
150             List<OFAction> actions = buildActions(bucket.treatment());
151
152             OFBucket.Builder bucketBuilder = factory.buildBucket();
153             bucketBuilder.setActions(actions);
154             if (type == GroupDescription.Type.SELECT) {
155                 bucketBuilder.setWeight(1);
156             }
157
158             if (type == GroupDescription.Type.FAILOVER && bucket.watchPort() != null) {
159                 bucketBuilder.setWatchPort(OFPort.of((int) bucket.watchPort().toLong()));
160             } else {
161                 bucketBuilder.setWatchPort(OFPort.ANY);
162             }
163             if (type == GroupDescription.Type.FAILOVER &&  bucket.watchGroup() != null) {
164                 bucketBuilder.setWatchGroup(OFGroup.of(bucket.watchGroup().id()));
165             } else {
166                 bucketBuilder.setWatchGroup(OFGroup.ANY);
167             }
168             OFBucket ofBucket = bucketBuilder.build();
169             ofBuckets.add(ofBucket);
170         }
171
172         OFGroupAdd groupMsg = factory.buildGroupAdd()
173                 .setGroup(OFGroup.of(groupId.id()))
174                 .setBuckets(ofBuckets)
175                 .setGroupType(getOFGroupType(type))
176                 .setXid(xid)
177                 .build();
178
179         return groupMsg;
180     }
181
182     /**
183      * Builds the GroupMod OF message.
184      *
185      * @return GroupMod OF message
186      */
187     public OFGroupMod buildGroupMod() {
188         List<OFBucket> ofBuckets = new ArrayList<OFBucket>();
189         for (GroupBucket bucket: buckets.buckets()) {
190             List<OFAction> actions = buildActions(bucket.treatment());
191
192             OFBucket.Builder bucketBuilder = factory.buildBucket();
193             bucketBuilder.setActions(actions);
194             if (type == GroupDescription.Type.SELECT) {
195                 bucketBuilder.setWeight(1);
196             }
197             bucketBuilder.setWatchGroup(OFGroup.ANY);
198             bucketBuilder.setWatchPort(OFPort.ANY);
199             OFBucket ofBucket = bucketBuilder.build();
200             ofBuckets.add(ofBucket);
201         }
202
203         OFGroupMod groupMsg = factory.buildGroupModify()
204                 .setGroup(OFGroup.of(groupId.id()))
205                 .setBuckets(ofBuckets)
206                 .setGroupType(getOFGroupType(type))
207                 .setXid(xid)
208                 .build();
209
210         return groupMsg;
211     }
212
213     /**
214      * Builds the GroupDel OF message.
215      *
216      * @return GroupDel OF message
217      */
218     public OFGroupDelete buildGroupDel() {
219
220         OFGroupDelete groupMsg = factory.buildGroupDelete()
221                 .setGroup(OFGroup.of(groupId.id()))
222                 .setGroupType(OFGroupType.SELECT)
223                 .setXid(xid)
224                 .build();
225
226         return groupMsg;
227     }
228
229     private List<OFAction> buildActions(TrafficTreatment treatment) {
230         if (treatment == null) {
231             return Collections.emptyList();
232         }
233
234         List<OFAction> actions = new LinkedList<>();
235         for (Instruction i : treatment.allInstructions()) {
236             switch (i.type()) {
237                 case DROP:
238                     log.warn("Saw drop action; assigning drop action");
239                     return Collections.emptyList();
240                 case L0MODIFICATION:
241                     actions.add(buildL0Modification(i));
242                     break;
243                 case L2MODIFICATION:
244                     actions.add(buildL2Modification(i));
245                     break;
246                 case L3MODIFICATION:
247                     actions.add(buildL3Modification(i));
248                     break;
249                 case OUTPUT:
250                     Instructions.OutputInstruction out =
251                             (Instructions.OutputInstruction) i;
252                     OFActionOutput.Builder action = factory.actions().buildOutput()
253                             .setPort(OFPort.of((int) out.port().toLong()));
254                     if (out.port().equals(PortNumber.CONTROLLER)) {
255                         action.setMaxLen(OFPCML_NO_BUFFER);
256                     }
257                     actions.add(action.build());
258                     break;
259                 case GROUP:
260                     Instructions.GroupInstruction grp =
261                             (Instructions.GroupInstruction) i;
262                     OFActionGroup.Builder actgrp = factory.actions().buildGroup()
263                             .setGroup(OFGroup.of(grp.groupId().id()));
264                     actions.add(actgrp.build());
265                     break;
266                 case EXTENSION:
267                     Instructions.ExtensionInstructionWrapper wrapper =
268                     (Instructions.ExtensionInstructionWrapper) i;
269                     actions.add(buildExtensionAction(
270                             wrapper.extensionInstruction(), wrapper.deviceId()));
271                     break;
272                 default:
273                     log.warn("Instruction type {} not yet implemented.", i.type());
274             }
275         }
276
277         return actions;
278     }
279
280     private OFAction buildL0Modification(Instruction i) {
281         L0ModificationInstruction l0m = (L0ModificationInstruction) i;
282         switch (l0m.subtype()) {
283             case LAMBDA:
284                 L0ModificationInstruction.ModLambdaInstruction ml =
285                         (L0ModificationInstruction.ModLambdaInstruction) i;
286                 return factory.actions().circuit(factory.oxms().ochSigidBasic(
287                         new CircuitSignalID((byte) 1, (byte) 2, ml.lambda(), (short) 1)));
288             default:
289                 log.warn("Unimplemented action type {}.", l0m.subtype());
290                 break;
291         }
292         return null;
293     }
294
295     private OFAction buildL2Modification(Instruction i) {
296         L2ModificationInstruction l2m = (L2ModificationInstruction) i;
297         L2ModificationInstruction.ModEtherInstruction eth;
298         OFOxm<?> oxm = null;
299         switch (l2m.subtype()) {
300             case ETH_DST:
301                 eth = (L2ModificationInstruction.ModEtherInstruction) l2m;
302                 oxm = factory.oxms().ethDst(MacAddress.of(eth.mac().toLong()));
303                 break;
304             case ETH_SRC:
305                 eth = (L2ModificationInstruction.ModEtherInstruction) l2m;
306                 oxm = factory.oxms().ethSrc(MacAddress.of(eth.mac().toLong()));
307                 break;
308             case VLAN_ID:
309                 L2ModificationInstruction.ModVlanIdInstruction vlanId =
310                         (L2ModificationInstruction.ModVlanIdInstruction) l2m;
311                 oxm = factory.oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanId.vlanId().toShort()));
312                 break;
313             case VLAN_PCP:
314                 L2ModificationInstruction.ModVlanPcpInstruction vlanPcp =
315                         (L2ModificationInstruction.ModVlanPcpInstruction) l2m;
316                 oxm = factory.oxms().vlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
317                 break;
318             case VLAN_POP:
319                 return factory.actions().popVlan();
320             case VLAN_PUSH:
321                 L2ModificationInstruction.PushHeaderInstructions pushVlanInstruction
322                         = (L2ModificationInstruction.PushHeaderInstructions) l2m;
323                 return factory.actions().pushVlan(
324                         EthType.of(pushVlanInstruction.ethernetType().toShort()));
325             case MPLS_PUSH:
326                 L2ModificationInstruction.PushHeaderInstructions pushHeaderInstructions =
327                         (L2ModificationInstruction.PushHeaderInstructions) l2m;
328                 return factory.actions().pushMpls(EthType.of(pushHeaderInstructions
329                                                              .ethernetType().toShort()));
330             case MPLS_POP:
331                 L2ModificationInstruction.PushHeaderInstructions popHeaderInstructions =
332                         (L2ModificationInstruction.PushHeaderInstructions) l2m;
333                 return factory.actions().popMpls(EthType.of(popHeaderInstructions
334                                                             .ethernetType().toShort()));
335             case MPLS_LABEL:
336                 L2ModificationInstruction.ModMplsLabelInstruction mplsLabel =
337                         (L2ModificationInstruction.ModMplsLabelInstruction) l2m;
338                 oxm = factory.oxms().mplsLabel(U32.of(mplsLabel.mplsLabel().toInt()));
339                 break;
340             case MPLS_BOS:
341                 L2ModificationInstruction.ModMplsBosInstruction mplsBos =
342                         (L2ModificationInstruction.ModMplsBosInstruction) l2m;
343                 oxm = factory.oxms()
344                         .mplsBos(mplsBos.mplsBos() ? OFBooleanValue.TRUE
345                                                    : OFBooleanValue.FALSE);
346                 break;
347             case DEC_MPLS_TTL:
348                 return factory.actions().decMplsTtl();
349             default:
350                 log.warn("Unimplemented action type {}.", l2m.subtype());
351                 break;
352         }
353
354         if (oxm != null) {
355             return factory.actions().buildSetField().setField(oxm).build();
356         }
357         return null;
358     }
359
360     private OFAction buildL3Modification(Instruction i) {
361         L3ModificationInstruction l3m = (L3ModificationInstruction) i;
362         L3ModificationInstruction.ModIPInstruction ip;
363         Ip4Address ip4;
364         Ip6Address ip6;
365         OFOxm<?> oxm = null;
366         switch (l3m.subtype()) {
367             case IPV4_SRC:
368                 ip = (L3ModificationInstruction.ModIPInstruction) i;
369                 ip4 = ip.ip().getIp4Address();
370                 oxm = factory.oxms().ipv4Src(IPv4Address.of(ip4.toInt()));
371                 break;
372             case IPV4_DST:
373                 ip = (L3ModificationInstruction.ModIPInstruction) i;
374                 ip4 = ip.ip().getIp4Address();
375                 oxm = factory.oxms().ipv4Dst(IPv4Address.of(ip4.toInt()));
376                 break;
377             case IPV6_SRC:
378                 ip = (L3ModificationInstruction.ModIPInstruction) i;
379                 ip6 = ip.ip().getIp6Address();
380                 oxm = factory.oxms().ipv6Src(IPv6Address.of(ip6.toOctets()));
381                 break;
382             case IPV6_DST:
383                 ip = (L3ModificationInstruction.ModIPInstruction) i;
384                 ip6 = ip.ip().getIp6Address();
385                 oxm = factory.oxms().ipv6Dst(IPv6Address.of(ip6.toOctets()));
386                 break;
387             case IPV6_FLABEL:
388                 L3ModificationInstruction.ModIPv6FlowLabelInstruction flowLabelInstruction =
389                     (L3ModificationInstruction.ModIPv6FlowLabelInstruction) i;
390                 int flowLabel = flowLabelInstruction.flowLabel();
391                 oxm = factory.oxms().ipv6Flabel(IPv6FlowLabel.of(flowLabel));
392                 break;
393             case DEC_TTL:
394                 return factory.actions().decNwTtl();
395             case TTL_IN:
396                 return factory.actions().copyTtlIn();
397             case TTL_OUT:
398                 return factory.actions().copyTtlOut();
399             default:
400                 log.warn("Unimplemented action type {}.", l3m.subtype());
401                 break;
402         }
403
404         if (oxm != null) {
405             return factory.actions().buildSetField().setField(oxm).build();
406         }
407         return null;
408     }
409
410     private OFGroupType getOFGroupType(GroupDescription.Type groupType) {
411         switch (groupType) {
412             case INDIRECT:
413                 return OFGroupType.INDIRECT;
414             case SELECT:
415                 return OFGroupType.SELECT;
416             case FAILOVER:
417                 return OFGroupType.FF;
418             case ALL:
419                 return OFGroupType.ALL;
420             default:
421                 log.error("Unsupported group type : {}", groupType);
422                 break;
423         }
424         return null;
425     }
426
427     private OFAction buildExtensionAction(ExtensionInstruction i, DeviceId deviceId) {
428         if (!driverService.isPresent()) {
429             log.error("No driver service present");
430             return null;
431         }
432         Driver driver = driverService.get().getDriver(deviceId);
433         if (driver.hasBehaviour(ExtensionInterpreter.class)) {
434             DefaultDriverHandler handler =
435                     new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
436             ExtensionInterpreter interpreter = handler.behaviour(ExtensionInterpreter.class);
437             return interpreter.mapInstruction(factory, i);
438         }
439
440         return null;
441     }
442 }
443