blob: b9124e8de973e50435b1151cb5b78a930b133c22 [file] [log] [blame]
Jonathan Hart1caaa932013-11-04 15:28:28 -08001package net.onrc.onos.ofcontroller.forwarding;
2
Jonathan Hartdc3ad702013-11-14 11:34:59 -08003import java.util.Collection;
Jonathan Hart1caaa932013-11-04 15:28:28 -08004import java.util.Iterator;
5
6import net.floodlightcontroller.core.FloodlightContext;
7import net.floodlightcontroller.core.IFloodlightProviderService;
8import net.floodlightcontroller.core.IOFMessageListener;
9import net.floodlightcontroller.core.IOFSwitch;
10import net.floodlightcontroller.packet.Ethernet;
11import net.floodlightcontroller.util.MACAddress;
Jonathan Hartdc3ad702013-11-14 11:34:59 -080012import net.onrc.onos.datagrid.IDatagridService;
Jonathan Hart1caaa932013-11-04 15:28:28 -080013import net.onrc.onos.ofcontroller.core.IDeviceStorage;
14import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
15import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
16import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
17import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
Jonathan Hart1caaa932013-11-04 15:28:28 -080018import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
19import net.onrc.onos.ofcontroller.topology.TopologyManager;
20import net.onrc.onos.ofcontroller.util.CallerId;
21import net.onrc.onos.ofcontroller.util.DataPath;
22import net.onrc.onos.ofcontroller.util.Dpid;
Jonathan Hart4fb16d82013-11-07 22:41:32 -080023import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
Jonathan Hart1caaa932013-11-04 15:28:28 -080024import net.onrc.onos.ofcontroller.util.FlowId;
25import net.onrc.onos.ofcontroller.util.FlowPath;
26import net.onrc.onos.ofcontroller.util.FlowPathType;
27import net.onrc.onos.ofcontroller.util.FlowPathUserState;
28import net.onrc.onos.ofcontroller.util.Port;
29import net.onrc.onos.ofcontroller.util.SwitchPort;
30
31import org.openflow.protocol.OFMessage;
32import org.openflow.protocol.OFPacketIn;
33import org.openflow.protocol.OFType;
34import org.openflow.util.HexString;
35import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
38public class Forwarding implements IOFMessageListener {
39 private final static Logger log = LoggerFactory.getLogger(Forwarding.class);
40
41 private IFloodlightProviderService floodlightProvider;
42 private IFlowService flowService;
Jonathan Hartdc3ad702013-11-14 11:34:59 -080043 private IDatagridService datagridService;
Jonathan Hart1caaa932013-11-04 15:28:28 -080044
45 private IDeviceStorage deviceStorage;
46 private TopologyManager topologyService;
47
Jonathan Hart4fb16d82013-11-07 22:41:32 -080048 // TODO Flow IDs should be globally managed
49 private long currentId = 1;
50
Jonathan Hart1caaa932013-11-04 15:28:28 -080051 public Forwarding() {
52
53 }
54
55 public void init(IFloodlightProviderService floodlightProvider,
Jonathan Hartdc3ad702013-11-14 11:34:59 -080056 IFlowService flowService, IDatagridService datagridService) {
Jonathan Hart1caaa932013-11-04 15:28:28 -080057 this.floodlightProvider = floodlightProvider;
58 this.flowService = flowService;
Jonathan Hartdc3ad702013-11-14 11:34:59 -080059 this.datagridService = datagridService;
Jonathan Hart1caaa932013-11-04 15:28:28 -080060
61 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
62
63 deviceStorage = new DeviceStorageImpl();
64 deviceStorage.init("");
65 topologyService = new TopologyManager();
66 topologyService.init("");
67 }
68
69 public void startUp() {
70 // no-op
71 }
72
73 @Override
74 public String getName() {
75 return "onosforwarding";
76 }
77
78 @Override
79 public boolean isCallbackOrderingPrereq(OFType type, String name) {
80 return (type == OFType.PACKET_IN) &&
81 (name.equals("devicemanager") || name.equals("proxyarpmanager"));
82 }
83
84 @Override
85 public boolean isCallbackOrderingPostreq(OFType type, String name) {
86 return false;
87 }
88
89 @Override
90 public Command receive(
91 IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
92
93 if (msg.getType() != OFType.PACKET_IN) {
94 return Command.CONTINUE;
95 }
96
97 OFPacketIn pi = (OFPacketIn) msg;
98
99 Ethernet eth = IFloodlightProviderService.bcStore.
100 get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
101
Jonathan Hart4fb16d82013-11-07 22:41:32 -0800102 // We only want to handle unicast IPv4
103 if (eth.isBroadcast() || eth.isMulticast() ||
104 eth.getEtherType() != Ethernet.TYPE_IPv4) {
Jonathan Hart1caaa932013-11-04 15:28:28 -0800105 return Command.CONTINUE;
106 }
107
108 handlePacketIn(sw, pi, eth);
109
110 return Command.STOP;
111 }
112
113 private void handlePacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
114 String destinationMac = HexString.toHexString(eth.getDestinationMACAddress());
115
116 IDeviceObject deviceObject = deviceStorage.getDeviceByMac(
117 destinationMac);
118
119 if (deviceObject == null) {
120 log.debug("No device entry found for {}", destinationMac);
121 return;
122 }
123
124 Iterator<IPortObject> ports = deviceObject.getAttachedPorts().iterator();
125 if (!ports.hasNext()) {
126 log.debug("No attachment point found for device {}", destinationMac);
127 return;
128 }
129 IPortObject portObject = ports.next();
130 short destinationPort = portObject.getNumber();
131 ISwitchObject switchObject = portObject.getSwitch();
132 long destinationDpid = HexString.toLong(switchObject.getDPID());
133
134 SwitchPort srcSwitchPort = new SwitchPort(
135 new Dpid(sw.getId()), new Port(pi.getInPort()));
136 SwitchPort dstSwitchPort = new SwitchPort(
137 new Dpid(destinationDpid), new Port(destinationPort));
Jonathan Hartdc3ad702013-11-14 11:34:59 -0800138
139 MACAddress srcMacAddress = MACAddress.valueOf(eth.getSourceMACAddress());
140 MACAddress dstMacAddress = MACAddress.valueOf(eth.getDestinationMACAddress());
Jonathan Hart1caaa932013-11-04 15:28:28 -0800141
Jonathan Hartdc3ad702013-11-14 11:34:59 -0800142 if (flowExists(srcSwitchPort, srcMacAddress,
143 dstSwitchPort, dstMacAddress)) {
144 log.debug("Not adding flow because it already exists");
145
146 // Don't do anything if the flow already exists
Jonathan Hart1caaa932013-11-04 15:28:28 -0800147 return;
148 }
149
Jonathan Hartdc3ad702013-11-14 11:34:59 -0800150 log.debug("Adding new flow between {} at {} and {} at {}",
151 new Object[]{srcMacAddress, srcSwitchPort, dstMacAddress, dstSwitchPort});
152
Jonathan Hart1caaa932013-11-04 15:28:28 -0800153
Jonathan Hart4fb16d82013-11-07 22:41:32 -0800154 DataPath dataPath = new DataPath();
155 dataPath.setSrcPort(srcSwitchPort);
156 dataPath.setDstPort(dstSwitchPort);
157
158 FlowId flowId = new FlowId(currentId++); //dummy flow ID
Jonathan Hart1caaa932013-11-04 15:28:28 -0800159 FlowPath flowPath = new FlowPath();
160 flowPath.setFlowId(flowId);
161 flowPath.setInstallerId(new CallerId("Forwarding"));
162 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
163 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
Jonathan Hart4fb16d82013-11-07 22:41:32 -0800164 flowPath.setFlowEntryMatch(new FlowEntryMatch());
Jonathan Hart1caaa932013-11-04 15:28:28 -0800165 flowPath.flowEntryMatch().enableSrcMac(srcMacAddress);
166 flowPath.flowEntryMatch().enableDstMac(dstMacAddress);
167 // For now just forward IPv4 packets. This prevents accidentally
168 // other stuff like ARP.
169 flowPath.flowEntryMatch().enableEthernetFrameType(Ethernet.TYPE_IPv4);
Jonathan Hart4fb16d82013-11-07 22:41:32 -0800170 flowPath.setDataPath(dataPath);
171
Jonathan Hart1caaa932013-11-04 15:28:28 -0800172 flowService.addFlow(flowPath, flowId);
Jonathan Hart1caaa932013-11-04 15:28:28 -0800173 }
Jonathan Hartdc3ad702013-11-14 11:34:59 -0800174
175 private boolean flowExists(SwitchPort srcPort, MACAddress srcMac,
176 SwitchPort dstPort, MACAddress dstMac) {
177 for (FlowPath flow : datagridService.getAllFlows()) {
178 FlowEntryMatch match = flow.flowEntryMatch();
179 // TODO implement FlowEntryMatch.equals();
180 // This is painful to do properly without support in the FlowEntryMatch
181 boolean same = true;
182 if (!match.srcMac().equals(srcMac) ||
183 !match.dstMac().equals(dstMac)) {
184 same = false;
185 }
186 if (!flow.dataPath().srcPort().equals(srcPort) ||
187 !flow.dataPath().dstPort().equals(dstPort)) {
188 same = false;
189 }
190
191 if (same) {
192 log.debug("found flow entry that's the same {}-{}:::{}-{}",
193 new Object[] {srcPort, srcMac, dstPort, dstMac});
194 return true;
195 }
196 }
197
198 return false;
199 }
Jonathan Hart1caaa932013-11-04 15:28:28 -0800200
201}