8fa4941b88771c94dbf3b578a3f89717339f899e
[controller.git] / opendaylight / protocol_plugins / openflow / src / main / java / org / opendaylight / controller / protocol_plugin / openflow / internal / FlowConverter.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.protocol_plugin.openflow.internal;
10
11 import java.math.BigInteger;
12 import java.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18
19 import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6FlowMod;
20 import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Match;
21 import org.opendaylight.controller.sal.action.Action;
22 import org.opendaylight.controller.sal.action.ActionType;
23 import org.opendaylight.controller.sal.action.Controller;
24 import org.opendaylight.controller.sal.action.Drop;
25 import org.opendaylight.controller.sal.action.Enqueue;
26 import org.opendaylight.controller.sal.action.Flood;
27 import org.opendaylight.controller.sal.action.FloodAll;
28 import org.opendaylight.controller.sal.action.HwPath;
29 import org.opendaylight.controller.sal.action.Loopback;
30 import org.opendaylight.controller.sal.action.Output;
31 import org.opendaylight.controller.sal.action.PopVlan;
32 import org.opendaylight.controller.sal.action.SetDlDst;
33 import org.opendaylight.controller.sal.action.SetDlSrc;
34 import org.opendaylight.controller.sal.action.SetNwDst;
35 import org.opendaylight.controller.sal.action.SetNwSrc;
36 import org.opendaylight.controller.sal.action.SetNwTos;
37 import org.opendaylight.controller.sal.action.SetTpDst;
38 import org.opendaylight.controller.sal.action.SetTpSrc;
39 import org.opendaylight.controller.sal.action.SetVlanId;
40 import org.opendaylight.controller.sal.action.SetVlanPcp;
41 import org.opendaylight.controller.sal.action.SwPath;
42 import org.opendaylight.controller.sal.core.Node;
43 import org.opendaylight.controller.sal.core.NodeConnector;
44 import org.opendaylight.controller.sal.flowprogrammer.Flow;
45 import org.opendaylight.controller.sal.match.Match;
46 import org.opendaylight.controller.sal.match.MatchField;
47 import org.opendaylight.controller.sal.match.MatchType;
48 import org.opendaylight.controller.sal.utils.NetUtils;
49 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
50 import org.openflow.protocol.OFFlowMod;
51 import org.openflow.protocol.OFMatch;
52 import org.openflow.protocol.OFMessage;
53 import org.openflow.protocol.OFPacketOut;
54 import org.openflow.protocol.OFPort;
55 import org.openflow.protocol.OFVendor;
56 import org.openflow.protocol.action.OFAction;
57 import org.openflow.protocol.action.OFActionDataLayer;
58 import org.openflow.protocol.action.OFActionDataLayerDestination;
59 import org.openflow.protocol.action.OFActionDataLayerSource;
60 import org.openflow.protocol.action.OFActionNetworkLayerAddress;
61 import org.openflow.protocol.action.OFActionNetworkLayerDestination;
62 import org.openflow.protocol.action.OFActionNetworkLayerSource;
63 import org.openflow.protocol.action.OFActionNetworkTypeOfService;
64 import org.openflow.protocol.action.OFActionOutput;
65 import org.openflow.protocol.action.OFActionStripVirtualLan;
66 import org.openflow.protocol.action.OFActionTransportLayer;
67 import org.openflow.protocol.action.OFActionTransportLayerDestination;
68 import org.openflow.protocol.action.OFActionTransportLayerSource;
69 import org.openflow.protocol.action.OFActionVirtualLanIdentifier;
70 import org.openflow.protocol.action.OFActionVirtualLanPriorityCodePoint;
71 import org.openflow.util.U16;
72 import org.openflow.util.U32;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
75
76 /**
77  * Utility class for converting a SAL Flow into the OF flow and vice-versa
78  */
79 public class FlowConverter {
80     protected static final Logger logger = LoggerFactory
81             .getLogger(FlowConverter.class);
82
83     /*
84      * The value 0xffff (OFP_VLAN_NONE) is used to indicate
85      * that no VLAN ID is set for OF Flow.
86      */
87     private static final short OFP_VLAN_NONE = (short) 0xffff;
88
89     private Flow flow; // SAL Flow
90     private OFMatch ofMatch; // OF 1.0 match or OF 1.0 + IPv6 extension match
91     private List<OFAction> actionsList; // OF 1.0 actions
92     private int actionsLength;
93     private boolean isIPv6;
94
95     public FlowConverter(OFMatch ofMatch, List<OFAction> actionsList) {
96         this.ofMatch = ofMatch;
97         this.actionsList = actionsList;
98         this.actionsLength = 0;
99         this.flow = null;
100         this.isIPv6 = ofMatch instanceof V6Match;
101     }
102
103     public FlowConverter(Flow flow) {
104         this.ofMatch = null;
105         this.actionsList = null;
106         this.actionsLength = 0;
107         this.flow = flow;
108         this.isIPv6 = flow.isIPv6();
109     }
110
111     /**
112      * Returns the match in OF 1.0 (OFMatch) form or OF 1.0 + IPv6 extensions
113      * form (V6Match)
114      *
115      * @return
116      */
117     public OFMatch getOFMatch() {
118         if (ofMatch == null) {
119             Match match = flow.getMatch();
120             ofMatch = (isIPv6) ? new V6Match() : new OFMatch();
121
122             int wildcards = OFMatch.OFPFW_ALL;
123             if (match.isPresent(MatchType.IN_PORT)) {
124                 short port = (Short) ((NodeConnector) match.getField(
125                         MatchType.IN_PORT).getValue()).getID();
126                 if (!isIPv6) {
127                     ofMatch.setInputPort(port);
128                     wildcards &= ~OFMatch.OFPFW_IN_PORT;
129                 } else {
130                     ((V6Match) ofMatch).setInputPort(port, (short) 0);
131                 }
132             }
133             if (match.isPresent(MatchType.DL_SRC)) {
134                 byte[] srcMac = (byte[]) match.getField(MatchType.DL_SRC)
135                         .getValue();
136                 if (!isIPv6) {
137                     ofMatch.setDataLayerSource(srcMac.clone());
138                     wildcards &= ~OFMatch.OFPFW_DL_SRC;
139                 } else {
140                     ((V6Match) ofMatch).setDataLayerSource(srcMac, null);
141                 }
142             }
143             if (match.isPresent(MatchType.DL_DST)) {
144                 byte[] dstMac = (byte[]) match.getField(MatchType.DL_DST)
145                         .getValue();
146                 if (!isIPv6) {
147                     ofMatch.setDataLayerDestination(dstMac.clone());
148                     wildcards &= ~OFMatch.OFPFW_DL_DST;
149                 } else {
150                     ((V6Match) ofMatch).setDataLayerDestination(dstMac, null);
151                 }
152             }
153             if (match.isPresent(MatchType.DL_VLAN)) {
154                 short vlan = (Short) match.getField(MatchType.DL_VLAN)
155                         .getValue();
156                 if (vlan == MatchType.DL_VLAN_NONE) {
157                     vlan = OFP_VLAN_NONE;
158                 }
159                 if (!isIPv6) {
160                     ofMatch.setDataLayerVirtualLan(vlan);
161                     wildcards &= ~OFMatch.OFPFW_DL_VLAN;
162                 } else {
163                     ((V6Match) ofMatch).setDataLayerVirtualLan(vlan, (short) 0);
164                 }
165             }
166             if (match.isPresent(MatchType.DL_VLAN_PR)) {
167                 byte vlanPr = (Byte) match.getField(MatchType.DL_VLAN_PR)
168                         .getValue();
169                 if (!isIPv6) {
170                     ofMatch.setDataLayerVirtualLanPriorityCodePoint(vlanPr);
171                     wildcards &= ~OFMatch.OFPFW_DL_VLAN_PCP;
172                 } else {
173                     ((V6Match) ofMatch)
174                             .setDataLayerVirtualLanPriorityCodePoint(vlanPr,
175                                     (byte) 0);
176                 }
177             }
178             if (match.isPresent(MatchType.DL_TYPE)) {
179                 short ethType = (Short) match.getField(MatchType.DL_TYPE)
180                         .getValue();
181                 if (!isIPv6) {
182                     ofMatch.setDataLayerType(ethType);
183                     wildcards &= ~OFMatch.OFPFW_DL_TYPE;
184                 } else {
185                     ((V6Match) ofMatch).setDataLayerType(ethType, (short) 0);
186                 }
187             }
188             if (match.isPresent(MatchType.NW_TOS)) {
189                 /*
190                  * OF 1.0 switch expects the TOS as the 6 msb in the byte. it is
191                  * actually the DSCP field followed by a zero ECN
192                  */
193                 byte tos = (Byte) match.getField(MatchType.NW_TOS).getValue();
194                 byte dscp = (byte) (tos << 2);
195                 if (!isIPv6) {
196                     ofMatch.setNetworkTypeOfService(dscp);
197                     wildcards &= ~OFMatch.OFPFW_NW_TOS;
198                 } else {
199                     ((V6Match) ofMatch).setNetworkTypeOfService(dscp, (byte) 0);
200                 }
201             }
202             if (match.isPresent(MatchType.NW_PROTO)) {
203                 byte proto = (Byte) match.getField(MatchType.NW_PROTO)
204                         .getValue();
205                 if (!isIPv6) {
206                     ofMatch.setNetworkProtocol(proto);
207                     wildcards &= ~OFMatch.OFPFW_NW_PROTO;
208                 } else {
209                     ((V6Match) ofMatch).setNetworkProtocol(proto, (byte) 0);
210                 }
211             }
212             if (match.isPresent(MatchType.NW_SRC)) {
213                 InetAddress address = (InetAddress) match.getField(MatchType.NW_SRC).getValue();
214                 InetAddress mask = (InetAddress) match.getField(MatchType.NW_SRC).getMask();
215                 if (!isIPv6) {
216                     ofMatch.setNetworkSource(NetUtils.byteArray4ToInt(address.getAddress()));
217                     int maskLength = (mask == null) ? 32 : NetUtils.getSubnetMaskLength(mask);
218                     wildcards = (wildcards & ~OFMatch.OFPFW_NW_SRC_MASK) | ((32 - maskLength) << OFMatch.OFPFW_NW_SRC_SHIFT);
219                 } else {
220                     ((V6Match) ofMatch).setNetworkSource(address, mask);
221                 }
222             }
223             if (match.isPresent(MatchType.NW_DST)) {
224                 InetAddress address = (InetAddress) match.getField(MatchType.NW_DST).getValue();
225                 InetAddress mask = (InetAddress) match.getField(MatchType.NW_DST).getMask();
226                 if (!isIPv6) {
227                     ofMatch.setNetworkDestination(NetUtils.byteArray4ToInt(address.getAddress()));
228                     int maskLength = (mask == null) ? 32 : NetUtils.getSubnetMaskLength(mask);
229                     wildcards = (wildcards & ~OFMatch.OFPFW_NW_DST_MASK) | ((32 - maskLength) << OFMatch.OFPFW_NW_DST_SHIFT);
230                 } else {
231                     ((V6Match) ofMatch).setNetworkDestination(address, mask);
232                 }
233             }
234             if (match.isPresent(MatchType.TP_SRC)) {
235                 short port = (Short) match.getField(MatchType.TP_SRC)
236                         .getValue();
237                 if (!isIPv6) {
238                     ofMatch.setTransportSource(port);
239                     wildcards &= ~OFMatch.OFPFW_TP_SRC;
240                 } else {
241                     ((V6Match) ofMatch).setTransportSource(port, (short) 0);
242                 }
243             }
244             if (match.isPresent(MatchType.TP_DST)) {
245                 short port = (Short) match.getField(MatchType.TP_DST)
246                         .getValue();
247                 if (!isIPv6) {
248                     ofMatch.setTransportDestination(port);
249                     wildcards &= ~OFMatch.OFPFW_TP_DST;
250                 } else {
251                     ((V6Match) ofMatch)
252                             .setTransportDestination(port, (short) 0);
253                 }
254             }
255
256             if (!isIPv6) {
257                 ofMatch.setWildcards(U32.t(Long.valueOf(wildcards)));
258             }
259         }
260         logger.trace("SAL Match: {} Openflow Match: {}", flow.getMatch(),
261                 ofMatch);
262         return ofMatch;
263     }
264
265     /**
266      * Returns the list of actions in OF 1.0 form
267      *
268      * @return
269      */
270     public List<OFAction> getOFActions() {
271         if (this.actionsList == null) {
272             actionsList = new ArrayList<OFAction>();
273             for (Action action : flow.getActions()) {
274                 if (action.getType() == ActionType.OUTPUT) {
275                     Output a = (Output) action;
276                     OFActionOutput ofAction = new OFActionOutput();
277                     ofAction.setMaxLength((short) 0xffff);
278                     ofAction.setPort(PortConverter.toOFPort(a.getPort()));
279                     actionsList.add(ofAction);
280                     actionsLength += OFActionOutput.MINIMUM_LENGTH;
281                     continue;
282                 }
283                 if (action.getType() == ActionType.DROP) {
284                     continue;
285                 }
286                 if (action.getType() == ActionType.LOOPBACK) {
287                     OFActionOutput ofAction = new OFActionOutput();
288                     ofAction.setPort(OFPort.OFPP_IN_PORT.getValue());
289                     actionsList.add(ofAction);
290                     actionsLength += OFActionOutput.MINIMUM_LENGTH;
291                     continue;
292                 }
293                 if (action.getType() == ActionType.FLOOD) {
294                     OFActionOutput ofAction = new OFActionOutput();
295                     ofAction.setPort(OFPort.OFPP_FLOOD.getValue());
296                     actionsList.add(ofAction);
297                     actionsLength += OFActionOutput.MINIMUM_LENGTH;
298                     continue;
299                 }
300                 if (action.getType() == ActionType.FLOOD_ALL) {
301                     OFActionOutput ofAction = new OFActionOutput();
302                     ofAction.setPort(OFPort.OFPP_ALL.getValue());
303                     actionsList.add(ofAction);
304                     actionsLength += OFActionOutput.MINIMUM_LENGTH;
305                     continue;
306                 }
307                 if (action.getType() == ActionType.CONTROLLER) {
308                     OFActionOutput ofAction = new OFActionOutput();
309                     ofAction.setPort(OFPort.OFPP_CONTROLLER.getValue());
310                     // We want the whole frame hitting the match be sent to the
311                     // controller
312                     ofAction.setMaxLength((short) 0xffff);
313                     actionsList.add(ofAction);
314                     actionsLength += OFActionOutput.MINIMUM_LENGTH;
315                     continue;
316                 }
317                 if (action.getType() == ActionType.SW_PATH) {
318                     OFActionOutput ofAction = new OFActionOutput();
319                     ofAction.setPort(OFPort.OFPP_LOCAL.getValue());
320                     actionsList.add(ofAction);
321                     actionsLength += OFActionOutput.MINIMUM_LENGTH;
322                     continue;
323                 }
324                 if (action.getType() == ActionType.HW_PATH) {
325                     OFActionOutput ofAction = new OFActionOutput();
326                     ofAction.setPort(OFPort.OFPP_NORMAL.getValue());
327                     actionsList.add(ofAction);
328                     actionsLength += OFActionOutput.MINIMUM_LENGTH;
329                     continue;
330                 }
331                 if (action.getType() == ActionType.SET_VLAN_ID) {
332                     SetVlanId a = (SetVlanId) action;
333                     OFActionVirtualLanIdentifier ofAction = new OFActionVirtualLanIdentifier();
334                     ofAction.setVirtualLanIdentifier((short) a.getVlanId());
335                     actionsList.add(ofAction);
336                     actionsLength += OFActionVirtualLanIdentifier.MINIMUM_LENGTH;
337                     continue;
338                 }
339                 if (action.getType() == ActionType.SET_VLAN_PCP) {
340                     SetVlanPcp a = (SetVlanPcp) action;
341                     OFActionVirtualLanPriorityCodePoint ofAction = new OFActionVirtualLanPriorityCodePoint();
342                     ofAction.setVirtualLanPriorityCodePoint(Integer.valueOf(
343                             a.getPcp()).byteValue());
344                     actionsList.add(ofAction);
345                     actionsLength += OFActionVirtualLanPriorityCodePoint.MINIMUM_LENGTH;
346                     continue;
347                 }
348                 if (action.getType() == ActionType.POP_VLAN) {
349                     OFActionStripVirtualLan ofAction = new OFActionStripVirtualLan();
350                     actionsList.add(ofAction);
351                     actionsLength += OFActionStripVirtualLan.MINIMUM_LENGTH;
352                     continue;
353                 }
354                 if (action.getType() == ActionType.SET_DL_SRC) {
355                     SetDlSrc a = (SetDlSrc) action;
356                     OFActionDataLayerSource ofAction = new OFActionDataLayerSource();
357                     ofAction.setDataLayerAddress(a.getDlAddress());
358                     actionsList.add(ofAction);
359                     actionsLength += OFActionDataLayer.MINIMUM_LENGTH;
360                     continue;
361                 }
362                 if (action.getType() == ActionType.SET_DL_DST) {
363                     SetDlDst a = (SetDlDst) action;
364                     OFActionDataLayerDestination ofAction = new OFActionDataLayerDestination();
365                     ofAction.setDataLayerAddress(a.getDlAddress());
366                     actionsList.add(ofAction);
367                     actionsLength += OFActionDataLayer.MINIMUM_LENGTH;
368                     continue;
369                 }
370                 if (action.getType() == ActionType.SET_NW_SRC) {
371                     SetNwSrc a = (SetNwSrc) action;
372                     OFActionNetworkLayerSource ofAction = new OFActionNetworkLayerSource();
373                     ofAction.setNetworkAddress(NetUtils.byteArray4ToInt(a
374                             .getAddress().getAddress()));
375                     actionsList.add(ofAction);
376                     actionsLength += OFActionNetworkLayerAddress.MINIMUM_LENGTH;
377                     continue;
378                 }
379                 if (action.getType() == ActionType.SET_NW_DST) {
380                     SetNwDst a = (SetNwDst) action;
381                     OFActionNetworkLayerDestination ofAction = new OFActionNetworkLayerDestination();
382                     ofAction.setNetworkAddress(NetUtils.byteArray4ToInt(a
383                             .getAddress().getAddress()));
384                     actionsList.add(ofAction);
385                     actionsLength += OFActionNetworkLayerAddress.MINIMUM_LENGTH;
386                     continue;
387                 }
388                 if (action.getType() == ActionType.SET_NW_TOS) {
389                     SetNwTos a = (SetNwTos) action;
390                     OFActionNetworkTypeOfService ofAction = new OFActionNetworkTypeOfService();
391                     ofAction.setNetworkTypeOfService(Integer.valueOf(
392                             a.getNwTos()).byteValue());
393                     actionsList.add(ofAction);
394                     actionsLength += OFActionNetworkTypeOfService.MINIMUM_LENGTH;
395                     continue;
396                 }
397                 if (action.getType() == ActionType.SET_TP_SRC) {
398                     SetTpSrc a = (SetTpSrc) action;
399                     OFActionTransportLayerSource ofAction = new OFActionTransportLayerSource();
400                     ofAction.setTransportPort(Integer.valueOf(a.getPort())
401                             .shortValue());
402                     actionsList.add(ofAction);
403                     actionsLength += OFActionTransportLayer.MINIMUM_LENGTH;
404                     continue;
405                 }
406                 if (action.getType() == ActionType.SET_TP_DST) {
407                     SetTpDst a = (SetTpDst) action;
408                     OFActionTransportLayerDestination ofAction = new OFActionTransportLayerDestination();
409                     ofAction.setTransportPort(Integer.valueOf(a.getPort())
410                             .shortValue());
411                     actionsList.add(ofAction);
412                     actionsLength += OFActionTransportLayer.MINIMUM_LENGTH;
413                     continue;
414                 }
415                 if (action.getType() == ActionType.SET_NEXT_HOP) {
416                     logger.info("Unsupported action: {}", action);
417                     continue;
418                 }
419             }
420         }
421         logger.trace("SAL Actions: {} Openflow Actions: {}", flow.getActions(),
422                 actionsList);
423         return actionsList;
424     }
425
426     /**
427      * Utility to convert a SAL flow to an OF 1.0 (OFFlowMod) or to an OF 1.0 +
428      * IPv6 extension (V6FlowMod) Flow modifier Message
429      *
430      * @param sw
431      * @param command
432      * @param port
433      * @return
434      */
435     public OFMessage getOFFlowMod(short command, OFPort port) {
436         OFMessage fm = (isIPv6) ? new V6FlowMod() : new OFFlowMod();
437         if (this.ofMatch == null) {
438             getOFMatch();
439         }
440         if (this.actionsList == null) {
441             getOFActions();
442         }
443         if (!isIPv6) {
444             ((OFFlowMod) fm).setMatch(this.ofMatch);
445             ((OFFlowMod) fm).setActions(this.actionsList);
446             ((OFFlowMod) fm).setPriority(flow.getPriority());
447             ((OFFlowMod) fm).setCookie(flow.getId());
448             ((OFFlowMod) fm).setBufferId(OFPacketOut.BUFFER_ID_NONE);
449             ((OFFlowMod) fm).setLength(U16.t(OFFlowMod.MINIMUM_LENGTH
450                     + actionsLength));
451             ((OFFlowMod) fm).setIdleTimeout(flow.getIdleTimeout());
452             ((OFFlowMod) fm).setHardTimeout(flow.getHardTimeout());
453             ((OFFlowMod) fm).setCommand(command);
454             if (port != null) {
455                 ((OFFlowMod) fm).setOutPort(port);
456             }
457             if (command == OFFlowMod.OFPFC_ADD || command == OFFlowMod.OFPFC_MODIFY
458                     || command == OFFlowMod.OFPFC_MODIFY_STRICT) {
459                 // Instruct switch to let controller know when flow is removed
460                 ((OFFlowMod) fm).setFlags((short) 1);
461             }
462         } else {
463             ((V6FlowMod) fm).setVendor();
464             ((V6FlowMod) fm).setMatch((V6Match) ofMatch);
465             ((V6FlowMod) fm).setActions(this.actionsList);
466             ((V6FlowMod) fm).setPriority(flow.getPriority());
467             ((V6FlowMod) fm).setCookie(flow.getId());
468             ((V6FlowMod) fm).setLength(U16.t(OFVendor.MINIMUM_LENGTH
469                     + ((V6Match) ofMatch).getIPv6ExtMinHdrLen()
470                     + ((V6Match) ofMatch).getIPv6MatchLen()
471                     + ((V6Match) ofMatch).getPadSize() + actionsLength));
472             ((V6FlowMod) fm).setIdleTimeout(flow.getIdleTimeout());
473             ((V6FlowMod) fm).setHardTimeout(flow.getHardTimeout());
474             ((V6FlowMod) fm).setCommand(command);
475             if (port != null) {
476                 ((V6FlowMod) fm).setOutPort(port);
477             }
478             if (command == OFFlowMod.OFPFC_ADD || command == OFFlowMod.OFPFC_MODIFY
479                     || command == OFFlowMod.OFPFC_MODIFY_STRICT) {
480                 // Instruct switch to let controller know when flow is removed
481                 ((V6FlowMod) fm).setFlags((short) 1);
482             }
483         }
484         logger.trace("Openflow Match: {} Openflow Actions: {}", ofMatch,
485                 actionsList);
486         logger.trace("Openflow Mod Message: {}", fm);
487         return fm;
488     }
489
490     public Flow getFlow(Node node) {
491         if (this.flow == null) {
492             Match salMatch = new Match();
493
494             /*
495              * Installed flow may not have a Match defined like in case of a
496              * drop all flow
497              */
498             if (ofMatch != null) {
499                 if (!isIPv6) {
500                     // Compute OF1.0 Match
501                     if (ofMatch.getInputPort() != 0 && ofMatch.getInputPort() != OFPort.OFPP_LOCAL.getValue()) {
502                         salMatch.setField(new MatchField(MatchType.IN_PORT,
503                                 NodeConnectorCreator.createNodeConnector(
504                                         ofMatch.getInputPort(), node)));
505                     }
506                     if (ofMatch.getDataLayerSource() != null
507                             && !NetUtils
508                                     .isZeroMAC(ofMatch.getDataLayerSource())) {
509                         byte srcMac[] = ofMatch.getDataLayerSource();
510                         salMatch.setField(new MatchField(MatchType.DL_SRC,
511                                 srcMac.clone()));
512                     }
513                     if (ofMatch.getDataLayerDestination() != null
514                             && !NetUtils.isZeroMAC(ofMatch
515                                     .getDataLayerDestination())) {
516                         byte dstMac[] = ofMatch.getDataLayerDestination();
517                         salMatch.setField(new MatchField(MatchType.DL_DST,
518                                 dstMac.clone()));
519                     }
520                     if (ofMatch.getDataLayerType() != 0) {
521                         salMatch.setField(new MatchField(MatchType.DL_TYPE,
522                                 ofMatch.getDataLayerType()));
523                     }
524                     short vlan = ofMatch.getDataLayerVirtualLan();
525                     if (vlan != 0) {
526                         if (vlan == OFP_VLAN_NONE) {
527                             vlan = MatchType.DL_VLAN_NONE;
528                         }
529                         salMatch.setField(new MatchField(MatchType.DL_VLAN,
530                                 vlan));
531                     }
532                     if (ofMatch.getDataLayerVirtualLanPriorityCodePoint() != 0) {
533                         salMatch.setField(MatchType.DL_VLAN_PR, ofMatch
534                                 .getDataLayerVirtualLanPriorityCodePoint());
535                     }
536                     if (ofMatch.getNetworkSource() != 0) {
537                         salMatch.setField(MatchType.NW_SRC, NetUtils
538                                 .getInetAddress(ofMatch.getNetworkSource()),
539                                 NetUtils.getInetNetworkMask(
540                                         ofMatch.getNetworkSourceMaskLen(),
541                                         false));
542                     }
543                     if (ofMatch.getNetworkDestination() != 0) {
544                         salMatch.setField(MatchType.NW_DST,
545                                 NetUtils.getInetAddress(ofMatch
546                                         .getNetworkDestination()),
547                                 NetUtils.getInetNetworkMask(
548                                         ofMatch.getNetworkDestinationMaskLen(),
549                                         false));
550                     }
551                     if (ofMatch.getNetworkTypeOfService() != 0) {
552                         int dscp = NetUtils.getUnsignedByte(ofMatch
553                                 .getNetworkTypeOfService());
554                         byte tos = (byte) (dscp >> 2);
555                         salMatch.setField(MatchType.NW_TOS, tos);
556                     }
557                     //TODO: NW protocol 0 is a valid protocol
558                     if (ofMatch.getNetworkProtocol() != 0) {
559                         salMatch.setField(MatchType.NW_PROTO,
560                                 ofMatch.getNetworkProtocol());
561                     }
562                     if (ofMatch.getTransportSource() != 0) {
563                         salMatch.setField(MatchType.TP_SRC,
564                                 ofMatch.getTransportSource());
565                     }
566                     if (ofMatch.getTransportDestination() != 0) {
567                         salMatch.setField(MatchType.TP_DST,
568                                 ofMatch.getTransportDestination());
569                     }
570                 } else {
571                     // Compute OF1.0 + IPv6 extensions Match
572                     V6Match v6Match = (V6Match) ofMatch;
573                     if (v6Match.getInputPort() != 0 && v6Match.getInputPort() != OFPort.OFPP_LOCAL.getValue()) {
574                         // Mask on input port is not defined
575                         salMatch.setField(new MatchField(MatchType.IN_PORT,
576                                 NodeConnectorCreator.createOFNodeConnector(
577                                         v6Match.getInputPort(), node)));
578                     }
579                     if (v6Match.getDataLayerSource() != null
580                             && !NetUtils
581                                     .isZeroMAC(ofMatch.getDataLayerSource())) {
582                         byte srcMac[] = v6Match.getDataLayerSource();
583                         salMatch.setField(new MatchField(MatchType.DL_SRC,
584                                 srcMac.clone()));
585                     }
586                     if (v6Match.getDataLayerDestination() != null
587                             && !NetUtils.isZeroMAC(ofMatch
588                                     .getDataLayerDestination())) {
589                         byte dstMac[] = v6Match.getDataLayerDestination();
590                         salMatch.setField(new MatchField(MatchType.DL_DST,
591                                 dstMac.clone()));
592                     }
593                     if (v6Match.getDataLayerType() != 0) {
594                         salMatch.setField(new MatchField(MatchType.DL_TYPE,
595                                 v6Match.getDataLayerType()));
596                     }
597                     short vlan = v6Match.getDataLayerVirtualLan();
598                     if (vlan != 0) {
599                         if (vlan == OFP_VLAN_NONE) {
600                             vlan = MatchType.DL_VLAN_NONE;
601                         }
602                         salMatch.setField(new MatchField(MatchType.DL_VLAN,
603                                 vlan));
604                     }
605                     if (v6Match.getDataLayerVirtualLanPriorityCodePoint() != 0) {
606                         salMatch.setField(MatchType.DL_VLAN_PR, v6Match
607                                 .getDataLayerVirtualLanPriorityCodePoint());
608                     }
609                     // V6Match may carry IPv4 address
610                     if (v6Match.getNetworkSrc() != null) {
611                         salMatch.setField(MatchType.NW_SRC,
612                                 v6Match.getNetworkSrc(),
613                                 v6Match.getNetworkSourceMask());
614                     } else if (v6Match.getNetworkSource() != 0) {
615                         salMatch.setField(MatchType.NW_SRC, NetUtils
616                                 .getInetAddress(v6Match.getNetworkSource()),
617                                 NetUtils.getInetNetworkMask(
618                                         v6Match.getNetworkSourceMaskLen(),
619                                         false));
620                     }
621                     // V6Match may carry IPv4 address
622                     if (v6Match.getNetworkDest() != null) {
623                         salMatch.setField(MatchType.NW_DST,
624                                 v6Match.getNetworkDest(),
625                                 v6Match.getNetworkDestinationMask());
626                     } else if (v6Match.getNetworkDestination() != 0) {
627                         salMatch.setField(MatchType.NW_DST,
628                                 NetUtils.getInetAddress(v6Match
629                                         .getNetworkDestination()),
630                                 NetUtils.getInetNetworkMask(
631                                         v6Match.getNetworkDestinationMaskLen(),
632                                         false));
633                     }
634                     if (v6Match.getNetworkTypeOfService() != 0) {
635                         int dscp = NetUtils.getUnsignedByte(v6Match
636                                 .getNetworkTypeOfService());
637                         byte tos = (byte) (dscp >> 2);
638                         salMatch.setField(MatchType.NW_TOS, tos);
639                     }
640                     if (v6Match.getNetworkProtocol() != 0) {
641                         salMatch.setField(MatchType.NW_PROTO,
642                                 v6Match.getNetworkProtocol());
643                     }
644                     if (v6Match.getTransportSource() != 0) {
645                         salMatch.setField(MatchType.TP_SRC,
646                                 (v6Match.getTransportSource()));
647                     }
648                     if (v6Match.getTransportDestination() != 0) {
649                         salMatch.setField(MatchType.TP_DST,
650                                 (v6Match.getTransportDestination()));
651                     }
652                 }
653             }
654
655             // Convert actions
656             Action salAction = null;
657             List<Action> salActionList = new ArrayList<Action>();
658             if (actionsList == null) {
659                 salActionList.add(new Drop());
660             } else {
661                 for (OFAction ofAction : actionsList) {
662                     if (ofAction instanceof OFActionOutput) {
663                         short ofPort = ((OFActionOutput) ofAction).getPort();
664                         if (ofPort == OFPort.OFPP_CONTROLLER.getValue()) {
665                             salAction = new Controller();
666                         } else if (ofPort == OFPort.OFPP_NONE.getValue()) {
667                             salAction = new Drop();
668                         } else if (ofPort == OFPort.OFPP_IN_PORT.getValue()) {
669                             salAction = new Loopback();
670                         } else if (ofPort == OFPort.OFPP_FLOOD.getValue()) {
671                             salAction = new Flood();
672                         } else if (ofPort == OFPort.OFPP_ALL.getValue()) {
673                             salAction = new FloodAll();
674                         } else if (ofPort == OFPort.OFPP_LOCAL.getValue()) {
675                             salAction = new SwPath();
676                         } else if (ofPort == OFPort.OFPP_NORMAL.getValue()) {
677                             salAction = new HwPath();
678                         } else if (ofPort == OFPort.OFPP_TABLE.getValue()) {
679                             salAction = new HwPath(); // TODO: we do not handle
680                                                       // table in sal for now
681                         } else {
682                             salAction = new Output(
683                                     NodeConnectorCreator.createOFNodeConnector(
684                                             ofPort, node));
685                         }
686                     } else if (ofAction instanceof OFActionVirtualLanIdentifier) {
687                         salAction = new SetVlanId(
688                                 ((OFActionVirtualLanIdentifier) ofAction)
689                                         .getVirtualLanIdentifier());
690                     } else if (ofAction instanceof OFActionStripVirtualLan) {
691                         salAction = new PopVlan();
692                     } else if (ofAction instanceof OFActionVirtualLanPriorityCodePoint) {
693                         salAction = new SetVlanPcp(
694                                 ((OFActionVirtualLanPriorityCodePoint) ofAction)
695                                         .getVirtualLanPriorityCodePoint());
696                     } else if (ofAction instanceof OFActionDataLayerSource) {
697                         salAction = new SetDlSrc(
698                                 ((OFActionDataLayerSource) ofAction)
699                                         .getDataLayerAddress().clone());
700                     } else if (ofAction instanceof OFActionDataLayerDestination) {
701                         salAction = new SetDlDst(
702                                 ((OFActionDataLayerDestination) ofAction)
703                                         .getDataLayerAddress().clone());
704                     } else if (ofAction instanceof OFActionNetworkLayerSource) {
705                         byte addr[] = BigInteger.valueOf(
706                                 ((OFActionNetworkLayerSource) ofAction)
707                                         .getNetworkAddress()).toByteArray();
708                         InetAddress ip = null;
709                         try {
710                             ip = InetAddress.getByAddress(addr);
711                         } catch (UnknownHostException e) {
712                             logger.error("", e);
713                         }
714                         salAction = new SetNwSrc(ip);
715                     } else if (ofAction instanceof OFActionNetworkLayerDestination) {
716                         byte addr[] = BigInteger.valueOf(
717                                 ((OFActionNetworkLayerDestination) ofAction)
718                                         .getNetworkAddress()).toByteArray();
719                         InetAddress ip = null;
720                         try {
721                             ip = InetAddress.getByAddress(addr);
722                         } catch (UnknownHostException e) {
723                             logger.error("", e);
724                         }
725                         salAction = new SetNwDst(ip);
726                     } else if (ofAction instanceof OFActionNetworkTypeOfService) {
727                         salAction = new SetNwTos(
728                                 ((OFActionNetworkTypeOfService) ofAction)
729                                         .getNetworkTypeOfService());
730                     } else if (ofAction instanceof OFActionTransportLayerSource) {
731                         Short port = ((OFActionTransportLayerSource) ofAction)
732                                 .getTransportPort();
733                         int intPort = NetUtils.getUnsignedShort(port);
734                         salAction = new SetTpSrc(intPort);
735                     } else if (ofAction instanceof OFActionTransportLayerDestination) {
736                         Short port = ((OFActionTransportLayerDestination) ofAction)
737                                 .getTransportPort();
738                         int intPort = NetUtils.getUnsignedShort(port);
739                         salAction = new SetTpDst(intPort);
740                     }
741                     salActionList.add(salAction);
742                 }
743             }
744             // Create Flow
745             flow = new Flow(salMatch, salActionList);
746         }
747         logger.trace("Openflow Match: {} Openflow Actions: {}", ofMatch,
748                 actionsList);
749         logger.trace("SAL Flow: {}", flow);
750         return flow;
751     }
752
753     private static final Map<Integer, Class<? extends Action>> actionMap = new HashMap<Integer, Class<? extends Action>>() {
754         private static final long serialVersionUID = 1L;
755         {
756             put(1 << 0, Output.class);
757             put(1 << 1, SetVlanId.class);
758             put(1 << 2, SetVlanPcp.class);
759             put(1 << 3, PopVlan.class);
760             put(1 << 4, SetDlSrc.class);
761             put(1 << 5, SetDlDst.class);
762             put(1 << 6, SetNwSrc.class);
763             put(1 << 7, SetNwDst.class);
764             put(1 << 8, SetNwTos.class);
765             put(1 << 9, SetTpSrc.class);
766             put(1 << 10, SetTpDst.class);
767             put(1 << 11, Enqueue.class);
768         }
769     };
770
771     /**
772      * Returns the supported flow actions for the netwrok node given the bitmask
773      * representing the actions the Openflow 1.0 switch supports
774      *
775      * @param ofActionBitmask
776      *            OF 1.0 action bitmask
777      * @return The correspondent list of SAL Action classes
778      */
779     public static List<Class<? extends Action>> getFlowActions(int ofActionBitmask) {
780         List<Class<? extends Action>> list = new ArrayList<Class<? extends Action>>();
781
782         for (int i = 0; i < Integer.SIZE; i++) {
783             int index = 1 << i;
784             if ((index & ofActionBitmask) > 0) {
785                 if (actionMap.containsKey(index)) {
786                     list.add(actionMap.get(index));
787                 }
788             }
789         }
790         // Add implicit SAL actions
791         list.add(Controller.class);
792         list.add(SwPath.class);
793         list.add(HwPath.class);
794         list.add(Drop.class);
795
796         return list;
797     }
798
799 }