blob: a3cb50eb9f9fdaa02c77f66f33262abb6e8c021e [file] [log] [blame]
Sangho Shin2f263692014-09-15 14:09:41 -07001package net.onrc.onos.apps.segmentrouting;
2
3import java.util.ArrayList;
Sangho Shin79c8d452014-09-18 09:50:21 -07004import java.util.LinkedList;
Sangho Shin2f263692014-09-15 14:09:41 -07005import java.util.List;
Sangho Shin79c8d452014-09-18 09:50:21 -07006import java.util.Queue;
7import java.util.Vector;
Sangho Shin2f263692014-09-15 14:09:41 -07008
9import net.floodlightcontroller.core.IFloodlightProviderService;
10import net.floodlightcontroller.core.IOFSwitch;
11import net.floodlightcontroller.core.module.FloodlightModuleContext;
12import net.floodlightcontroller.util.MACAddress;
13import net.onrc.onos.api.packet.IPacketListener;
14import net.onrc.onos.api.packet.IPacketService;
15import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
16import net.onrc.onos.core.packet.Ethernet;
Sangho Shin79c8d452014-09-18 09:50:21 -070017import net.onrc.onos.core.packet.ICMP;
Sangho Shin2f263692014-09-15 14:09:41 -070018import net.onrc.onos.core.packet.IPv4;
19import net.onrc.onos.core.topology.ITopologyService;
Sangho Shin79c8d452014-09-18 09:50:21 -070020import net.onrc.onos.core.topology.Link;
Sangho Shin2f263692014-09-15 14:09:41 -070021import net.onrc.onos.core.topology.MutableTopology;
22import net.onrc.onos.core.topology.Port;
23import net.onrc.onos.core.topology.Switch;
Sangho Shin79c8d452014-09-18 09:50:21 -070024import net.onrc.onos.core.util.Dpid;
25import net.onrc.onos.core.util.SwitchPort;
Sangho Shin2f263692014-09-15 14:09:41 -070026
27import org.projectfloodlight.openflow.protocol.OFFactory;
28import org.projectfloodlight.openflow.protocol.OFMatchV3;
29import org.projectfloodlight.openflow.protocol.OFMessage;
30import org.projectfloodlight.openflow.protocol.OFOxmList;
31import org.projectfloodlight.openflow.protocol.action.OFAction;
32import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
33import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
34import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
35import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
36import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
37import org.projectfloodlight.openflow.types.EthType;
38import org.projectfloodlight.openflow.types.IPv4Address;
39import org.projectfloodlight.openflow.types.MacAddress;
40import org.projectfloodlight.openflow.types.OFBufferId;
41import org.projectfloodlight.openflow.types.OFPort;
42import org.projectfloodlight.openflow.types.TableId;
43import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
45
46public class IcmpHandler implements IPacketListener {
47
48 private SegmentRoutingManager srManager;
49 private IFloodlightProviderService floodlightProvider;
50 private MutableTopology mutableTopology;
51 private IPacketService packetService;
52 private ITopologyService topologyService;
53 private static final Logger log = LoggerFactory
54 .getLogger(ArpHandler.class);
55
56 private IFlowPusherService flowPusher;
57
58 private static final int TABLE_VLAN = 0;
59 private static final int TABLE_TMAC = 1;
60 private static final int TABLE_IPv4_UNICAST = 2;
61 private static final int TABLE_MPLS = 3;
62 private static final int TABLE_META = 4;
63 private static final int TABLE_ACL = 5;
64
65 private static final short MAX_PRIORITY = (short) 0xffff;
66 private static final short SLASH_24_PRIORITY = (short) 0xfff0;
67 private static final short SLASH_16_PRIORITY = (short) 0xff00;
68 private static final short SLASH_8_PRIORITY = (short) 0xf000;
69 private static final short MIN_PRIORITY = 0x0;
70
71
72 public IcmpHandler(FloodlightModuleContext context, SegmentRoutingManager manager) {
73
74 this.floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
75 this.flowPusher = context.getServiceImpl(IFlowPusherService.class);
76 this.packetService = context.getServiceImpl(IPacketService.class);
77 this.topologyService = context.getServiceImpl(ITopologyService.class);
78 this.mutableTopology = topologyService.getTopology();
79
80 this.srManager = manager;
81
82 packetService.registerPacketListener(this);
83
84 }
85
86 @Override
87 public void receive(Switch sw, Port inPort, Ethernet payload) {
88
89 if (payload.getEtherType() == Ethernet.TYPE_IPV4) {
90
91 IPv4 ipv4 = (IPv4)payload.getPayload();
Sangho Shin79c8d452014-09-18 09:50:21 -070092
Sangho Shin2f263692014-09-15 14:09:41 -070093 if (ipv4.getProtocol() == IPv4.PROTOCOL_ICMP) {
Sangho Shin79c8d452014-09-18 09:50:21 -070094 int destinationAddress = ipv4.getDestinationAddress();
Sangho Shin2f263692014-09-15 14:09:41 -070095
Sangho Shin79c8d452014-09-18 09:50:21 -070096 // Check if it is ICMP request to the switch
97 String switchIpAddressSlash = sw.getStringAttribute("routerIp");
98 if (switchIpAddressSlash != null) {
99 String switchIpAddressStr = switchIpAddressSlash.substring(0, switchIpAddressSlash.indexOf('/'));
100 IPv4Address switchIpAddress = IPv4Address.of(switchIpAddressStr);
Sangho Shin2f263692014-09-15 14:09:41 -0700101
Sangho Shin79c8d452014-09-18 09:50:21 -0700102 if (((ICMP)ipv4.getPayload()).getIcmpType() == 0x08 &&
103 destinationAddress == switchIpAddress.getInt()) {
104 sendICMPResponse(sw, inPort, payload);
105 return;
106 }
107 }
108
109 // Check if the destination is any host known to TopologyService
110 for (net.onrc.onos.core.topology.Host host: mutableTopology.getHosts()) {
111 IPv4Address hostIpAddress = IPv4Address.of(host.getIpAddress());
112 if (hostIpAddress != null && hostIpAddress.getInt() == destinationAddress) {
113 byte[] destinationMacAddress = host.getMacAddress().toBytes();
114 addRouteToHost(sw, destinationAddress, destinationMacAddress);
115 return;
116 }
117 }
118
119 // What if the ICMP destination is neither to switch nor known to TopologyService ??
120 lookupPath(sw, inPort);
Sangho Shin2f263692014-09-15 14:09:41 -0700121 }
122
123 }
124
125 }
126
Sangho Shin79c8d452014-09-18 09:50:21 -0700127
128 /**
129 * Test method for ECMP path computation
130 *
131 */
132 private void lookupPath(Switch sw, Port inPort) {
133 // TODO Auto-generated method stub
134
135 Queue<Dpid> switchQueue = new LinkedList();
136 Vector<Dpid> switchVectorDone = new Vector();
137 switchQueue.add(sw.getDpid());
138 Dpid dpid = null;
139 Switch s = null;
140
141 dpid = sw.getDpid();
142 while (dpid != null) {
143 s = mutableTopology.getSwitch(dpid);
144 for (Port port : mutableTopology.getPorts(s.getDpid())) {
145 SwitchPort sport1 = new SwitchPort(port.getDpid(), port.getPortNumber());
146 for (Link link : mutableTopology.getOutgoingLinks(sport1)) {
147 if (!switchVectorDone.contains(link.getDstSwitch().getDpid())) {
148 log.debug("{} --- {} ",link.getSrcSwitch().getDpid(), link.getDstSwitch().getDpid());
149 switchQueue.add(link.getDstSwitch().getDpid());
150 }
151 }
152 }
153 switchVectorDone.add(s.getDpid());
154 dpid = s.getDpid();
155 switchQueue.remove(dpid);
156 dpid = switchQueue.poll();
157
158 }
159
160
161 }
162
163 /**
164 * Send ICMP reply back
165 *
166 * @param sw Switch
167 * @param inPort Port the ICMP packet is forwarded from
168 * @param icmpRequest the ICMP request to handle
169 * @param destinationAddress destination address to send ICMP response to
170 */
171 private void sendICMPResponse(Switch sw, Port inPort, Ethernet icmpRequest) {
172
173 Ethernet icmpReplyEth = new Ethernet();
174
175 IPv4 icmpRequestIpv4 = (IPv4) icmpRequest.getPayload();
176 IPv4 icmpReplyIpv4 = new IPv4();
177 int destAddress = icmpRequestIpv4.getDestinationAddress();
178 icmpReplyIpv4.setDestinationAddress(icmpRequestIpv4.getSourceAddress());
179 icmpReplyIpv4.setSourceAddress(destAddress);
180 icmpReplyIpv4.setTtl((byte)64);
181 icmpReplyIpv4.setChecksum((short)0);
182
183
184 ICMP icmpReply = (ICMP)icmpRequestIpv4.getPayload().clone();
185 icmpReply.setIcmpCode((byte)0x00);
186 icmpReply.setIcmpType((byte) 0x00);
187 icmpReply.setChecksum((short)0);
188
189 icmpReplyIpv4.setPayload(icmpReply);
190
191 icmpReplyEth.setPayload(icmpReplyIpv4);
192 icmpReplyEth.setEtherType(Ethernet.TYPE_IPV4);
193 icmpReplyEth.setDestinationMACAddress(icmpRequest.getSourceMACAddress());
194 icmpReplyEth.setSourceMACAddress(icmpRequest.getDestinationMACAddress());
195
196 packetService.sendPacket(icmpReplyEth, new SwitchPort(sw.getDpid(), inPort.getPortNumber()));
197
198 log.debug("Send an ICMP response {}", icmpReplyIpv4.toString());
199
200 }
201
202
Sangho Shin2f263692014-09-15 14:09:41 -0700203 /**
204 * Add routing rules to forward packets to known hosts
205 *
206 * @param sw Switch
207 * @param hostIp Host IP address to forwards packets to
208 */
Sangho Shin79c8d452014-09-18 09:50:21 -0700209 private void addRouteToHost(Switch sw, int destinationAddress, byte[] destinationMacAddress) {
Sangho Shin2f263692014-09-15 14:09:41 -0700210
211 IOFSwitch ofSwitch = floodlightProvider.getMasterSwitch(sw.getDpid().value());
212 OFFactory factory = ofSwitch.getFactory();
Sangho Shin2f263692014-09-15 14:09:41 -0700213
Sangho Shin2f263692014-09-15 14:09:41 -0700214
215 OFOxmEthType ethTypeIp = factory.oxms()
216 .ethType(EthType.IPv4);
217 OFOxmIpv4DstMasked ipPrefix = factory.oxms()
218 .ipv4DstMasked(
219 IPv4Address.of(destinationAddress),
220 IPv4Address.NO_MASK); // host addr should be /32
221 OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
222 OFMatchV3 match = factory.buildMatchV3()
223 .setOxmList(oxmListSlash32).build();
224 OFAction setDmac = null;
225 OFOxmEthDst dmac = factory.oxms()
226 .ethDst(MacAddress.of(destinationMacAddress));
227 setDmac = factory.actions().buildSetField()
228 .setField(dmac).build();
229
230 OFAction decTtl = factory.actions().decNwTtl();
231
232 // Set the source MAC address with the switch MAC address
233 String switchMacAddress = sw.getStringAttribute("routerMac");
234 OFOxmEthSrc srcAddr = factory.oxms().ethSrc(MacAddress.of(switchMacAddress));
235 OFAction setSA = factory.actions().buildSetField()
236 .setField(srcAddr).build();
237
238 List<OFAction> actionList = new ArrayList<OFAction>();
239 actionList.add(setDmac);
240 actionList.add(decTtl);
241 actionList.add(setSA);
242
243
244 /* TODO : need to check the config file for all packets
245 String subnets = sw.getStringAttribute("subnets");
246 try {
247 JSONArray arry = new JSONArray(subnets);
248 for (int i = 0; i < arry.length(); i++) {
249 String subnetIp = (String) arry.getJSONObject(i).get("subnetIp");
250 int portNo = (int) arry.getJSONObject(i).get("portNo");
251
252 if (netMatch(subnetIp, IPv4Address.of(hostIp.getDestinationAddress()).toString())) {
253 OFAction out = factory.actions().buildOutput()
254 .setPort(OFPort.of(portNo)).build();
255 actionList.add(out);
256 }
257 }
258 } catch (JSONException e) {
259 // TODO Auto-generated catch block
260 e.printStackTrace();
261 }
262 */
263
264 // Set output port
265 net.onrc.onos.core.topology.Host host = mutableTopology.getHostByMac(MACAddress.valueOf(destinationMacAddress));
266 if (host != null) {
267 for (Port port: host.getAttachmentPoints()) {
268 OFAction out = factory.actions().buildOutput()
269 .setPort(OFPort.of(port.getPortNumber().shortValue())).build();
270 actionList.add(out);
271 }
272 }
273
274 OFInstruction writeInstr = factory.instructions().buildWriteActions()
275 .setActions(actionList).build();
276
277 List<OFInstruction> instructions = new ArrayList<OFInstruction>();
278 instructions.add(writeInstr);
279
280 OFMessage myIpEntry = factory.buildFlowAdd()
281 .setTableId(TableId.of(TABLE_IPv4_UNICAST))
282 .setMatch(match)
283 .setInstructions(instructions)
284 .setPriority(MAX_PRIORITY)
285 .setBufferId(OFBufferId.NO_BUFFER)
286 .setIdleTimeout(0)
287 .setHardTimeout(0)
288 //.setXid(getNextTransactionId())
289 .build();
290
291 log.debug("Sending 'Routing information' OF message to the switch {}.", sw.getDpid().toString());
292
293 flowPusher.add(sw.getDpid(), myIpEntry);
294
295
296 }
297
298}