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