014a9276d79ddcb4ba47c3e4120a0684a362bd45
[l2switch.git] / arphandler / src / main / java / org / opendaylight / l2switch / arphandler / core / PacketDispatcher.java
1 /*
2  * Copyright (c) 2014 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.l2switch.arphandler.core;
10
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.JdkFutureAdapters;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import java.util.List;
16 import org.opendaylight.l2switch.arphandler.inventory.InventoryReader;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
27 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
28 import org.opendaylight.yangtools.yang.common.RpcResult;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33  * PacketDispatcher sends packets out to the network.
34  */
35 public class PacketDispatcher {
36
37     private static final Logger LOG = LoggerFactory.getLogger(PacketDispatcher.class);
38     private InventoryReader inventoryReader;
39     private PacketProcessingService packetProcessingService;
40
41     public void setPacketProcessingService(PacketProcessingService packetProcessingService) {
42         this.packetProcessingService = packetProcessingService;
43     }
44
45     public void setInventoryReader(InventoryReader inventoryReader) {
46         this.inventoryReader = inventoryReader;
47     }
48
49     /**
50      * Dispatches the packet in the appropriate way - flood or unicast.
51      *
52      * @param payload
53      *            The payload to be sent.
54      * @param ingress
55      *            The NodeConnector where the payload came from.
56      * @param srcMac
57      *            The source MacAddress of the packet.
58      * @param destMac
59      *            The destination MacAddress of the packet.
60      */
61     public void dispatchPacket(byte[] payload, NodeConnectorRef ingress, MacAddress srcMac, MacAddress destMac) {
62         inventoryReader.readInventory();
63
64         String nodeId = ingress.getValue().firstIdentifierOf(Node.class).firstKeyOf(Node.class, NodeKey.class).getId()
65                 .getValue();
66         NodeConnectorRef srcConnectorRef = inventoryReader.getControllerSwitchConnectors().get(nodeId);
67
68         if (srcConnectorRef == null) {
69             refreshInventoryReader();
70             srcConnectorRef = inventoryReader.getControllerSwitchConnectors().get(nodeId);
71         }
72         NodeConnectorRef destNodeConnector = inventoryReader
73                 .getNodeConnector(ingress.getValue().firstIdentifierOf(Node.class), destMac);
74         if (srcConnectorRef != null) {
75             if (destNodeConnector != null) {
76                 sendPacketOut(payload, srcConnectorRef, destNodeConnector);
77             } else {
78                 floodPacket(nodeId, payload, ingress, srcConnectorRef);
79             }
80         } else {
81             LOG.info("Cannot send packet out or flood as controller node connector is not available for node {}.",
82                     nodeId);
83         }
84     }
85
86     /**
87      * Floods the packet.
88      *
89      * @param nodeId
90      *            The node id
91      * @param payload
92      *            The payload to be sent.
93      * @param origIngress
94      *            The NodeConnector where the payload came from.
95      */
96     public void floodPacket(String nodeId, byte[] payload, NodeConnectorRef origIngress,
97             NodeConnectorRef controllerNodeConnector) {
98
99         List<NodeConnectorRef> nodeConnectors = inventoryReader.getSwitchNodeConnectors().get(nodeId);
100
101         if (nodeConnectors == null) {
102             refreshInventoryReader();
103             nodeConnectors = inventoryReader.getSwitchNodeConnectors().get(nodeId);
104             if (nodeConnectors == null) {
105                 LOG.info("Cannot flood packets, as inventory doesn't have any node connectors for node {}", nodeId);
106                 return;
107             }
108         }
109         for (NodeConnectorRef ncRef : nodeConnectors) {
110             String ncId = ncRef.getValue().firstIdentifierOf(NodeConnector.class)
111                     .firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue();
112             // Don't flood on discarding node connectors & origIngress
113             if (!ncId.equals(origIngress.getValue().firstIdentifierOf(NodeConnector.class)
114                     .firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue())) {
115                 sendPacketOut(payload, origIngress, ncRef);
116             }
117         }
118     }
119
120     /**
121      * Sends the specified packet on the specified port.
122      *
123      * @param payload
124      *            The payload to be sent.
125      * @param ingress
126      *            The NodeConnector where the payload came from.
127      * @param egress
128      *            The NodeConnector where the payload will go.
129      */
130     public void sendPacketOut(byte[] payload, NodeConnectorRef ingress, NodeConnectorRef egress) {
131         if (ingress == null || egress == null) {
132             return;
133         }
134         InstanceIdentifier<Node> egressNodePath = getNodePath(egress.getValue());
135         TransmitPacketInput input = new TransmitPacketInputBuilder() //
136                 .setPayload(payload) //
137                 .setNode(new NodeRef(egressNodePath)) //
138                 .setEgress(egress) //
139                 .setIngress(ingress) //
140                 .build();
141
142         Futures.addCallback(JdkFutureAdapters.listenInPoolThread(packetProcessingService.transmitPacket(input)),
143             new FutureCallback<RpcResult<Void>>() {
144                 @Override
145                 public void onSuccess(RpcResult<Void> result) {
146                     LOG.debug("transmitPacket was successful");
147                 }
148
149                 @Override
150                 public void onFailure(Throwable failure) {
151                     LOG.debug("transmitPacket for {} failed", input, failure);
152                 }
153             }, MoreExecutors.directExecutor());
154     }
155
156     private void refreshInventoryReader() {
157         inventoryReader.setRefreshData(true);
158         inventoryReader.readInventory();
159     }
160
161     private InstanceIdentifier<Node> getNodePath(final InstanceIdentifier<?> nodeChild) {
162         return nodeChild.firstIdentifierOf(Node.class);
163     }
164
165 }