24679eadb3a968d98ac909895172a8c8ead3e43b
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / PacketOutConvertor.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 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor;
9
10 import com.google.common.collect.Iterables;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.Optional;
16 import java.util.Set;
17 import org.opendaylight.controller.sal.common.util.Arguments;
18 import org.opendaylight.openflowplugin.api.OFConstants;
19 import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
20 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.action.data.ActionConvertorData;
21 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.Convertor;
22 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.XidConvertorData;
23 import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.action.grouping.action.choice.OutputActionCaseBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.action.grouping.action.choice.output.action._case.OutputActionBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.Action;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203.actions.grouping.ActionBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortNumber;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketOutInput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketOutInputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
36 import org.opendaylight.yangtools.yang.common.Uint32;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * Converts a MD-SAL packet out data into the OF library packet out input.
42  *
43  * <p>
44  * Example usage:
45  * <pre>
46  * {@code
47  * XidConvertorData data = new XidConvertorData(version);
48  * data.setDatapathId(datapathId);
49  * data.setXid(xid);
50  * Optional<PacketOutInput> ofPacketInput = convertorManager.convert(salPacket, data);
51  * }
52  * </pre>
53  */
54 public class PacketOutConvertor extends Convertor<TransmitPacketInput, PacketOutInput, XidConvertorData> {
55     private static final Logger LOG = LoggerFactory.getLogger(PacketOutConvertor.class);
56     private static final Set<Class<?>> TYPES = Collections.singleton(TransmitPacketInput.class);
57     private static final PortNumber CONTROLLER_PORT = new PortNumber(Uint32.valueOf(0xfffffffdL).intern());
58
59     /**
60      * Create default empty meter mot input builder.
61      * Use this method, if result from convertor is empty.
62      *
63      * @param version Openflow version
64      * @return default empty meter mod input builder
65      */
66     public static PacketOutInput defaultResult(final short version) {
67         return new PacketOutInputBuilder()
68                 .setVersion(version)
69                 .build();
70     }
71
72     private static PortNumber getPortNumber(final PathArgument pathArgument, final Short ofVersion) {
73         // FIXME VD P! find InstanceIdentifier helper
74         InstanceIdentifier.IdentifiableItem<?, ?> item = Arguments.checkInstanceOf(pathArgument,
75                 InstanceIdentifier.IdentifiableItem.class);
76         NodeConnectorKey key = Arguments.checkInstanceOf(item.getKey(), NodeConnectorKey.class);
77         Uint32 port = InventoryDataServiceUtil.portNumberfromNodeConnectorId(
78                 OpenflowVersion.get(ofVersion), key.getId());
79         return new PortNumber(port);
80     }
81
82     @Override
83     public Collection<Class<?>> getTypes() {
84         return TYPES;
85     }
86
87     @Override
88     public PacketOutInput convert(final TransmitPacketInput source, final XidConvertorData data) {
89         LOG.trace("toPacketOutInput for datapathId:{}, xid:{}", data.getDatapathId(), data.getXid());
90         // Build Port ID from TransmitPacketInput.Ingress
91         PortNumber inPortNr;
92         Uint32 bufferId = OFConstants.OFP_NO_BUFFER;
93         Iterable<PathArgument> inArgs = null;
94
95         if (source.getIngress() != null) {
96             inArgs = source.getIngress().getValue().getPathArguments();
97         }
98
99         if (inArgs != null && Iterables.size(inArgs) >= 3) {
100             inPortNr = getPortNumber(Iterables.get(inArgs, 2), data.getVersion());
101         } else {
102             // The packetOut originated from the controller
103             inPortNr = CONTROLLER_PORT;
104         }
105
106         // Build Buffer ID to be NO_OFP_NO_BUFFER
107         if (source.getBufferId() != null) {
108             bufferId = source.getBufferId();
109         }
110
111         PortNumber outPort = null;
112         NodeConnectorRef outRef = source.getEgress();
113         Iterable<PathArgument> outArgs = outRef.getValue().getPathArguments();
114
115         if (Iterables.size(outArgs) >= 3) {
116             outPort = getPortNumber(Iterables.get(outArgs, 2), data.getVersion());
117         } else {
118             // TODO : P4 search for some normal exception
119             // new Exception("PORT NR not exist in Egress");
120             LOG.error("PORT NR not exist in Egress");
121         }
122
123         List<Action> actions = new ArrayList<>();
124         List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> inputActions =
125                 source.getAction();
126
127         if (inputActions != null) {
128             final ActionConvertorData actionConvertorData = new ActionConvertorData(data.getVersion());
129             actionConvertorData.setDatapathId(data.getDatapathId());
130
131             final Optional<List<Action>> convertedActions = getConvertorExecutor().convert(
132                     inputActions, actionConvertorData);
133
134             actions = convertedActions.orElse(Collections.emptyList());
135
136         } else {
137             // TODO VD P! wait for way to move Actions (e.g. augmentation)
138             OutputActionCaseBuilder outputActionCaseBuilder = new OutputActionCaseBuilder();
139             OutputActionBuilder outputActionBuilder = new OutputActionBuilder();
140             outputActionBuilder.setPort(outPort);
141             outputActionBuilder.setMaxLength(OFConstants.OFPCML_NO_BUFFER);
142             outputActionCaseBuilder.setOutputAction(outputActionBuilder.build());
143             ActionBuilder actionBuild = new ActionBuilder();
144             actionBuild.setActionChoice(outputActionCaseBuilder.build());
145             actions.add(actionBuild.build());
146         }
147
148         PacketOutInputBuilder builder = new PacketOutInputBuilder();
149         builder.setAction(actions);
150         builder.setData(source.getPayload());
151         builder.setVersion(data.getVersion());
152         builder.setXid(data.getXid());
153         builder.setInPort(inPortNr);
154         builder.setBufferId(bufferId);
155
156         return builder.build();
157     }
158 }