425ba6fe243a5fbb9e3d7ad0d419f88153d41065
[affinity.git] / l2agent / src / main / java / org / opendaylight / l2agent / L2Agent.java
1 /*
2  * Copyright (c) 2013 Plexxi, Inc. and others.  All rights reserved.
3  */
4
5 /*
6  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
7  *
8  * This program and the accompanying materials are made available under the
9  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
10  * and is available at http://www.eclipse.org/legal/epl-v10.html
11  */
12
13 /*
14  * Adapted from tutorial L2 forwarding demo (http://archive.openflow.org/).
15  */
16 package org.opendaylight.affinity.l2agent;
17
18 import java.net.InetAddress;
19 import java.net.UnknownHostException;
20 import java.util.List;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashSet;
24 import java.util.Set;
25 import java.lang.String;
26 import java.util.Map;
27 import java.util.HashMap;
28 import java.util.Timer;
29 import java.util.TimerTask;
30 import java.util.concurrent.ConcurrentHashMap;
31
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 import org.opendaylight.controller.sal.core.ConstructionException;
36 import org.opendaylight.controller.sal.core.Node;
37 import org.opendaylight.controller.sal.core.NodeConnector;
38 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
39 import org.opendaylight.controller.sal.flowprogrammer.Flow;
40 import org.opendaylight.controller.sal.packet.ARP;
41 import org.opendaylight.controller.sal.packet.BitBufferHelper;
42 import org.opendaylight.controller.sal.packet.Ethernet;
43 import org.opendaylight.controller.sal.packet.IDataPacketService;
44 import org.opendaylight.controller.sal.packet.IListenDataPacket;
45 import org.opendaylight.controller.sal.packet.Packet;
46 import org.opendaylight.controller.sal.packet.PacketResult;
47 import org.opendaylight.controller.sal.packet.RawPacket;
48 import org.opendaylight.controller.sal.action.Action;
49 import org.opendaylight.controller.sal.action.Output;
50 import org.opendaylight.controller.sal.action.Flood;
51 import org.opendaylight.controller.sal.match.Match;
52 import org.opendaylight.controller.sal.match.MatchType;
53 import org.opendaylight.controller.sal.match.MatchField;
54 import org.opendaylight.controller.sal.utils.EtherTypes;
55 import org.opendaylight.controller.sal.utils.Status;
56 import org.opendaylight.controller.sal.utils.NetUtils;
57 import org.opendaylight.controller.switchmanager.ISwitchManager;
58 import org.opendaylight.controller.switchmanager.Subnet;
59
60 public class L2Agent implements IListenDataPacket {
61     private static final Logger logger = LoggerFactory
62             .getLogger(L2Agent.class);
63     private ISwitchManager switchManager = null;
64     private IFlowProgrammerService programmer = null;
65     private IDataPacketService dataPacketService = null;
66     private Map<Long, NodeConnector> mac_to_port = new HashMap<Long, NodeConnector>();
67     private String function = "switch";
68
69     void setDataPacketService(IDataPacketService s) {
70         this.dataPacketService = s;
71     }
72
73     void unsetDataPacketService(IDataPacketService s) {
74         if (this.dataPacketService == s) {
75             this.dataPacketService = null;
76         }
77     }
78
79     public void setFlowProgrammerService(IFlowProgrammerService s)
80     {
81         this.programmer = s;
82     }
83
84     public void unsetFlowProgrammerService(IFlowProgrammerService s) {
85         if (this.programmer == s) {
86             this.programmer = null;
87         }
88     }
89
90     void setSwitchManager(ISwitchManager s) {
91         logger.debug("SwitchManager set");
92         this.switchManager = s;
93     }
94
95     void unsetSwitchManager(ISwitchManager s) {
96         if (this.switchManager == s) {
97             logger.debug("SwitchManager removed!");
98             this.switchManager = null;
99         }
100     }
101
102     /**
103      * Function called by the dependency manager when all the required
104      * dependencies are satisfied
105      *
106      */
107     void init() {
108         logger.info("Initialized");
109     }
110
111     /**
112      * Function called by the dependency manager when at least one
113      * dependency become unsatisfied or when the component is shutting
114      * down because for example bundle is being stopped.
115      *
116      */
117     void destroy() {
118     }
119
120     /**
121      * Function called by dependency manager after "init ()" is called
122      * and after the services provided by the class are registered in
123      * the service registry
124      *
125      */
126     void start() {
127         logger.info("Started");
128     }
129
130     /**
131      * Function called by the dependency manager before the services
132      * exported by the component are unregistered, this will be
133      * followed by a "destroy ()" calls
134      *
135      */
136     void stop() {
137         logger.info("Stopped");
138     }
139
140     private void floodPacket(RawPacket inPkt) {
141         NodeConnector incoming_connector = inPkt.getIncomingNodeConnector();
142         Node incoming_node = incoming_connector.getNode();
143
144         Set<NodeConnector> nodeConnectors =
145                 this.switchManager.getUpNodeConnectors(incoming_node);
146
147         for (NodeConnector p : nodeConnectors) {
148             if (!p.equals(incoming_connector)) {
149                 try {
150                     RawPacket destPkt = new RawPacket(inPkt);
151                     destPkt.setOutgoingNodeConnector(p);
152                     this.dataPacketService.transmitDataPacket(destPkt);
153                 } catch (ConstructionException e2) {
154                     continue;
155                 }
156             }
157         }
158     }
159
160     @Override
161     public PacketResult receiveDataPacket(RawPacket inPkt) {
162         if (inPkt == null) {
163             return PacketResult.IGNORED;
164         }
165         logger.trace("Received a frame of size: {}",
166                         inPkt.getPacketData().length);
167
168         Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
169         NodeConnector incoming_connector = inPkt.getIncomingNodeConnector();
170         Node incoming_node = incoming_connector.getNode();
171
172         if (formattedPak instanceof Ethernet) {
173             byte[] srcMAC = ((Ethernet)formattedPak).getSourceMACAddress();
174             byte[] dstMAC = ((Ethernet)formattedPak).getDestinationMACAddress();
175
176             // Hub implementation
177             if (function.equals("hub")) {
178                 floodPacket(inPkt);
179                 return PacketResult.CONSUME;
180             }
181
182             // Switch
183             else {
184                 long srcMAC_val = BitBufferHelper.toNumber(srcMAC);
185                 long dstMAC_val = BitBufferHelper.toNumber(dstMAC);
186
187                 this.mac_to_port.put(srcMAC_val, incoming_connector);
188
189                 Match match = new Match();
190                 match.setField( new MatchField(MatchType.IN_PORT, incoming_connector) );
191                 match.setField( new MatchField(MatchType.DL_DST, dstMAC.clone()) );
192
193                 NodeConnector dst_connector;
194
195                 // Do I know the destination MAC?
196                 if ((dst_connector = this.mac_to_port.get(dstMAC_val)) != null) {
197                     List<Action> actions = new ArrayList<Action>();
198                     actions.add(new Output(dst_connector));
199
200                     Flow f = new Flow(match, actions);
201
202                     // Modify the flow on the network node
203                     Status status = programmer.addFlow(incoming_node, f);
204                     if (!status.isSuccess()) {
205                         logger.warn(
206                                 "SDN Plugin failed to program the flow: {}. The failure is: {}",
207                                 f, status.getDescription());
208                         return PacketResult.IGNORED;
209                     }
210                     logger.info("Installed flow {} in node {}",
211                             f, incoming_node);
212                 }
213                 else
214                     floodPacket(inPkt);
215             }
216         }
217         return PacketResult.IGNORED;
218     }
219
220     /*
221      * Return MAC adderss to port
222      */
223     public NodeConnector lookupMacAddress(byte[] macAddress) {
224         NodeConnector dst_connector;
225         return this.mac_to_port.get(macAddress);
226     }
227 }