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