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