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