blob: 517126cef245c684916eea3316387a845974e5f9 [file] [log] [blame]
pingping-lina2cbfad2013-03-07 08:39:21 +08001package net.floodlightcontroller.bgproute;
2
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07003import java.io.IOException;
4import java.net.InetAddress;
Jonathan Hart61ba9372013-05-19 20:10:29 -07005import java.net.UnknownHostException;
pingping-lina2cbfad2013-03-07 08:39:21 +08006import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07007import java.util.Collection;
pingping-lina2cbfad2013-03-07 08:39:21 +08008import java.util.HashMap;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07009import java.util.HashSet;
10import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070011import java.util.Map;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070012import java.util.Set;
pingping-lina2cbfad2013-03-07 08:39:21 +080013
Jonathan Hart61ba9372013-05-19 20:10:29 -070014import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070015import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
16import net.floodlightcontroller.core.IOFSwitch;
pingping-lina2cbfad2013-03-07 08:39:21 +080017import net.floodlightcontroller.core.module.FloodlightModuleContext;
18import net.floodlightcontroller.core.module.FloodlightModuleException;
19import net.floodlightcontroller.core.module.IFloodlightModule;
20import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070021import net.floodlightcontroller.devicemanager.IDeviceService;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +120022import net.floodlightcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070023import net.floodlightcontroller.packet.Ethernet;
pingping-lina2cbfad2013-03-07 08:39:21 +080024import net.floodlightcontroller.restserver.IRestApiService;
25import net.floodlightcontroller.topology.ITopologyListener;
26import net.floodlightcontroller.topology.ITopologyService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070027import net.floodlightcontroller.util.DataPath;
28import net.floodlightcontroller.util.Dpid;
29import net.floodlightcontroller.util.FlowEntry;
30import net.floodlightcontroller.util.IPv4;
31import net.floodlightcontroller.util.MACAddress;
32import net.floodlightcontroller.util.Port;
33import net.floodlightcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080034import net.sf.json.JSONArray;
35import net.sf.json.JSONObject;
36import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080037
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070038import org.openflow.protocol.OFFlowMod;
39import org.openflow.protocol.OFMatch;
40import org.openflow.protocol.OFMessage;
41import org.openflow.protocol.OFPacketOut;
42import org.openflow.protocol.OFType;
43import org.openflow.protocol.action.OFAction;
44import org.openflow.protocol.action.OFActionDataLayerDestination;
45import org.openflow.protocol.action.OFActionOutput;
pingping-lina2cbfad2013-03-07 08:39:21 +080046import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070049import com.google.common.net.InetAddresses;
50
pingping-lina2cbfad2013-03-07 08:39:21 +080051public class BgpRoute implements IFloodlightModule, IBgpRouteService, ITopologyListener {
52
53 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
54
55 protected IFloodlightProviderService floodlightProvider;
56 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070057 protected ITopoRouteService topoRouteService;
58 protected IDeviceService devices;
59 protected IRestApiService restApi;
60
pingping-lina2cbfad2013-03-07 08:39:21 +080061 protected static Ptree ptree;
Jonathan Hart61ba9372013-05-19 20:10:29 -070062 protected String bgpdRestIp;
63 protected String routerId;
pingping-line2a09ca2013-03-23 09:33:58 +080064
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070065 protected Set<InetAddress> routerIpAddresses;
66
67 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
68 //the controller/OS should hand out cookie IDs to prevent conflicts.
69 protected final long APP_COOKIE = 0xa0000000000000L;
70 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
71 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
72 //Cookie for flows in ingress switches that rewrite the MAC address
73 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +120074 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
75 //need to be higher priority than this otherwise the rewrite may not get done
76 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070077
78 //TODO temporary
79 protected List<GatewayRouter> gatewayRouters;
80
81 private void initGateways(){
82 gatewayRouters = new ArrayList<GatewayRouter>();
83 //00:00:00:00:00:00:0s0:a3 port 1
84 gatewayRouters.add(
85 new GatewayRouter(new SwitchPort(new Dpid(163L), new Port((short)1)),
86 new MACAddress(new byte[] {0x00, 0x00, 0x00, 0x00, 0x02, 0x01}),
Jonathan Hart50a8d1e2013-06-06 16:00:47 +120087 new IPv4("192.168.10.1"),
88 new MACAddress(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}),
89 new IPv4("192.168.10.101")));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070090 //00:00:00:00:00:00:00:a5 port 1
91 //gatewayRouters.add(new SwitchPort(new Dpid(165L), new Port((short)1)));
92 gatewayRouters.add(
93 new GatewayRouter(new SwitchPort(new Dpid(165L), new Port((short)1)),
94 new MACAddress(new byte[] {0x00, 0x00, 0x00, 0x00, 0x02, 0x02}),
Jonathan Hart50a8d1e2013-06-06 16:00:47 +120095 new IPv4("192.168.20.1"),
96 new MACAddress(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}),
97 new IPv4("192.168.20.101")));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070098 //00:00:00:00:00:00:00:a2 port 1
99 //gatewayRouters.add(new SwitchPort(new Dpid(162L), new Port((short)1)));
100 gatewayRouters.add(
101 new GatewayRouter(new SwitchPort(new Dpid(162L), new Port((short)1)),
102 new MACAddress(new byte[] {0x00, 0x00, 0x00, 0x00, 0x03, 0x01}),
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200103 new IPv4("192.168.30.1"),
104 new MACAddress(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}),
105 new IPv4("192.168.30.101")));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700106 //00:00:00:00:00:00:00:a6
107 //gatewayRouters.add(new SwitchPort(new Dpid(166L), new Port((short)1)));
108 gatewayRouters.add(
109 new GatewayRouter(new SwitchPort(new Dpid(166L), new Port((short)1)),
110 new MACAddress(new byte[] {0x00, 0x00, 0x00, 0x00, 0x04, 0x01}),
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200111 new IPv4("192.168.40.1"),
112 new MACAddress(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x04}),
113 new IPv4("192.168.40.101")));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700114
115 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800116
117 @Override
118 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700119 Collection<Class<? extends IFloodlightService>> l
120 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800121 l.add(IBgpRouteService.class);
122 return l;
123 }
124
125 @Override
126 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700127 Map<Class<? extends IFloodlightService>, IFloodlightService> m
128 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800129 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800130 return m;
131 }
132
pingping-lina2cbfad2013-03-07 08:39:21 +0800133 @Override
134 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700135 Collection<Class<? extends IFloodlightService>> l
136 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800137 l.add(IFloodlightProviderService.class);
138 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700139 l.add(ITopoRouteService.class);
140 l.add(IDeviceService.class);
141 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800142 return l;
143 }
144
145 @Override
146 public void init(FloodlightModuleContext context)
147 throws FloodlightModuleException {
148
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700149 initGateways();
150
pingping-lina2cbfad2013-03-07 08:39:21 +0800151 ptree = new Ptree(32);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700152
153 routerIpAddresses = new HashSet<InetAddress>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800154
155 // Register floodlight provider and REST handler.
156 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800157 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700158 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
159 devices = context.getServiceImpl(IDeviceService.class);
160 restApi = context.getServiceImpl(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800161
Jonathan Hart61ba9372013-05-19 20:10:29 -0700162 //Read in config values
163 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
164 if (bgpdRestIp == null){
165 log.error("BgpdRestIp property not found in config file");
166 System.exit(1);
167 }
168 else {
169 log.info("BgpdRestIp set to {}", bgpdRestIp);
170 }
171
172 routerId = context.getConfigParams(this).get("RouterId");
173 if (routerId == null){
174 log.error("RouterId property not found in config file");
175 System.exit(1);
176 }
177 else {
178 log.info("RouterId set to {}", routerId);
179 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800180 // Test.
181 //test();
182 }
183
184 public Ptree getPtree() {
185 return ptree;
186 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700187
188 public void clearPtree() {
189 //ptree = null;
190 ptree = new Ptree(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800191 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700192
pingping-line2a09ca2013-03-23 09:33:58 +0800193 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700194 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800195 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700196
pingping-line2a09ca2013-03-23 09:33:58 +0800197 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700198 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800199 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800200
201 // Return nexthop address as byte array.
202 public Rib lookupRib(byte[] dest) {
203 if (ptree == null) {
204 log.debug("lookupRib: ptree null");
205 return null;
206 }
207
208 PtreeNode node = ptree.match(dest, 32);
209 if (node == null) {
210 log.debug("lookupRib: ptree node null");
211 return null;
212 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700213
pingping-lina2cbfad2013-03-07 08:39:21 +0800214 if (node.rib == null) {
215 log.debug("lookupRib: ptree rib null");
216 return null;
217 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700218
pingping-lina2cbfad2013-03-07 08:39:21 +0800219 ptree.delReference(node);
220
221 return node.rib;
222 }
223
Jonathan Hart61ba9372013-05-19 20:10:29 -0700224 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800225 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700226 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800227 System.out.println("Here it is");
228 Prefix p = new Prefix("128.0.0.0", 8);
229 Prefix q = new Prefix("8.0.0.0", 8);
230 Prefix r = new Prefix("10.0.0.0", 24);
231 Prefix a = new Prefix("10.0.0.1", 32);
232
233 ptree.acquire(p.getAddress(), p.masklen);
234 ptree.acquire(q.getAddress(), q.masklen);
235 ptree.acquire(r.getAddress(), r.masklen);
236
237 System.out.println("Traverse start");
238 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
239 Prefix p_result = new Prefix(node.key, node.keyBits);
240 }
241
242 PtreeNode n = ptree.match(a.getAddress(), a.masklen);
243 if (n != null) {
244 System.out.println("Matched prefix for 10.0.0.1:");
245 Prefix x = new Prefix(n.key, n.keyBits);
246 ptree.delReference(n);
247 }
248
249 n = ptree.lookup(p.getAddress(), p.masklen);
250 if (n != null) {
251 ptree.delReference(n);
252 ptree.delReference(n);
253 }
254 System.out.println("Traverse start");
255 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
256 Prefix p_result = new Prefix(node.key, node.keyBits);
257 }
258
259 n = ptree.lookup(q.getAddress(), q.masklen);
260 if (n != null) {
261 ptree.delReference(n);
262 ptree.delReference(n);
263 }
264 System.out.println("Traverse start");
265 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
266 Prefix p_result = new Prefix(node.key, node.keyBits);
267 }
268
269 n = ptree.lookup(r.getAddress(), r.masklen);
270 if (n != null) {
271 ptree.delReference(n);
272 ptree.delReference(n);
273 }
274 System.out.println("Traverse start");
275 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
276 Prefix p_result = new Prefix(node.key, node.keyBits);
277 }
278
279 }
280
Jonathan Hart61ba9372013-05-19 20:10:29 -0700281 private void retrieveRib(){
282 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
283 String response = RestClient.get(url);
284
285 if (response.equals("")){
286 return;
287 }
288
289 response = response.replaceAll("\"", "'");
290 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
291 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
292 String router_id = jsonObj.getString("router-id");
293
294 int size = rib_json_array.size();
295
296 log.info("Retrived RIB of {} entries from BGPd", size);
297
298 for (int j = 0; j < size; j++) {
299 JSONObject second_json_object = rib_json_array.getJSONObject(j);
300 String prefix = second_json_object.getString("prefix");
301 String nexthop = second_json_object.getString("nexthop");
302
303 //insert each rib entry into the local rib;
304 String[] substring = prefix.split("/");
305 String prefix1 = substring[0];
306 String mask1 = substring[1];
307
308 Prefix p;
309 try {
310 p = new Prefix(prefix1, Integer.valueOf(mask1));
311 } catch (NumberFormatException e) {
312 log.warn("Wrong mask format in RIB JSON: {}", mask1);
313 continue;
314 } catch (UnknownHostException e1) {
315 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
316 continue;
317 }
318
319 PtreeNode node = ptree.acquire(p.getAddress(), p.masklen);
320 Rib rib = new Rib(router_id, nexthop, p.masklen);
321
322 if (node.rib != null) {
323 node.rib = null;
324 ptree.delReference(node);
325 }
326
327 node.rib = rib;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700328
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200329 prefixAdded(node);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700330 }
331 }
332
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200333 public void prefixAdded(PtreeNode node) {
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700334 //Add a flow to rewrite mac for this prefix to all border switches
335 GatewayRouter thisRouter = null;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200336 for (GatewayRouter router : gatewayRouters){
337 if (router.getRouterIp().value() ==
338 InetAddresses.coerceToInteger(node.rib.nextHop)){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700339 thisRouter = router;
340 break;
341 }
342 }
343
344 if (thisRouter == null){
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200345 //TODO local router isn't in gateway list so this will get thrown
346 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
347 log.error("Couldn't find next hop router in router {} in config"
348 , node.rib.nextHop.toString());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700349 return; //just quit out here? This is probably a configuration error
350 }
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200351
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700352 for (GatewayRouter ingressRouter : gatewayRouters){
353 if (ingressRouter == thisRouter) {
354 continue;
355 }
356
357 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200358 ingressRouter.getAttachmentPoint(),
359 thisRouter.getAttachmentPoint());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700360
361 if (shortestPath == null){
362 log.debug("Shortest path between {} and {} not found",
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200363 ingressRouter.getAttachmentPoint(),
364 thisRouter.getAttachmentPoint());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700365 return; // just quit here?
366 }
367
368 //TODO check the shortest path against the cached version we
369 //calculated before. If they don't match up that's a problem
370
371 //Set up the flow mod
372 OFFlowMod fm =
373 (OFFlowMod) floodlightProvider.getOFMessageFactory()
374 .getMessage(OFType.FLOW_MOD);
375
376 fm.setIdleTimeout((short)0)
377 .setHardTimeout((short)0)
378 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
379 .setCookie(MAC_RW_COOKIE)
380 .setCommand(OFFlowMod.OFPFC_ADD)
381 //.setMatch(match)
382 //.setActions(actions)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200383 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700384 .setLengthU(OFFlowMod.MINIMUM_LENGTH
385 + OFActionDataLayerDestination.MINIMUM_LENGTH
386 + OFActionOutput.MINIMUM_LENGTH);
387
388 OFMatch match = new OFMatch();
389 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200390 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700391
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200392 match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
393 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
394
395 //match.setDataLayerDestination(ingressRouter.getSdnRouterMac().toBytes());
396 //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
397
398 InetAddress address = null;
399 try {
400 address = InetAddress.getByAddress(node.key);
401 } catch (UnknownHostException e1) {
402 //Should never happen is the reverse conversion has already been done
403 log.error("Malformed IP address");
404 return;
405 }
406
407 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
408 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700409
410 //Set up MAC rewrite action
411 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
412 macRewriteAction.setDataLayerAddress(thisRouter.getRouterMac().toBytes());
413
414 //Set up output action
415 OFActionOutput outputAction = new OFActionOutput();
416 outputAction.setMaxLength((short)0xffff); //TODO check what this is (and if needed for mac rewrite)
417
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200418 Port outputPort = shortestPath.flowEntries().get(0).outPort();
419 outputAction.setPort(outputPort.value());
420
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700421 List<OFAction> actions = new ArrayList<OFAction>();
422 actions.add(macRewriteAction);
423 actions.add(outputAction);
424 fm.setActions(actions);
425
426 //Write to switch
427 IOFSwitch sw = floodlightProvider.getSwitches()
428 .get(ingressRouter.getAttachmentPoint().dpid().value());
429
430 if (sw == null){
431 log.warn("Switch not found when pushing flow mod");
432 continue;
433 }
434
435 List<OFMessage> msglist = new ArrayList<OFMessage>();
436 msglist.add(fm);
437 try {
438 sw.write(msglist, null);
439 sw.flush();
440 } catch (IOException e) {
441 log.error("Failure writing flow mod", e);
442 }
443 }
444 }
445
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200446 public void prefixDeleted(PtreeNode node) {
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700447 //Remove MAC rewriting flows from other border switches
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200448
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700449 }
450
451 /*
452 * On startup we need to calculate a full mesh of paths between all gateway
453 * switches
454 */
455 private void calculateFullMesh(){
456 Map<IOFSwitch, SwitchPort> gatewaySwitches = new HashMap<IOFSwitch, SwitchPort>();
457
458 //have to account for switches not being there, paths not being found.
459
460 //for (SwitchPort switchPort : gatewayRouters){
461 for (GatewayRouter router : gatewayRouters){
462 SwitchPort switchPort = router.getAttachmentPoint();
463
464 IOFSwitch sw = floodlightProvider.getSwitches().get(switchPort.dpid().value());
465
466 if (sw == null){
467 log.debug("Gateway switch {} not here yet", switchPort.dpid().value());
468 return; // just quit here?
469 }
470
471 //Only need to know 1 external-facing port from each gateway switch
472 //which we can feed into shortest path calculation
473 if (!gatewaySwitches.containsKey(sw)){
474 gatewaySwitches.put(sw, switchPort);
475 }
476
477 }
478 log.debug("size {}", gatewaySwitches.size());
479
480 //For each border router, calculate and install a path from every other
481 //border switch to said border router. However, don't install the entry
482 //in to the first hop switch, as we need to install an entry to rewrite
483 //for each prefix received. This will be done later when prefixes have
484 //actually been received.
485
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700486 for (GatewayRouter dstRouter : gatewayRouters){
487 SwitchPort routerAttachmentPoint = dstRouter.getAttachmentPoint();
488 for (Map.Entry<IOFSwitch, SwitchPort> src : gatewaySwitches.entrySet()) {
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700489
490 if (routerAttachmentPoint.dpid().value() ==
491 src.getKey().getId()){
492 continue;
493 }
494
495 DataPath shortestPath = topoRouteService.getShortestPath(
496 src.getValue(), routerAttachmentPoint);
497
498 if (shortestPath == null){
499 log.debug("Shortest path between {} and {} not found",
500 src.getValue(), routerAttachmentPoint);
501 return; // just quit here?
502 }
503
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700504 //install flows
505 installPath(shortestPath.flowEntries(), dstRouter);
506 }
507 }
508 }
509
510 private void installPath(List<FlowEntry> flowEntries, GatewayRouter router){
511
512 //Set up the flow mod
513 OFFlowMod fm =
514 (OFFlowMod) floodlightProvider.getOFMessageFactory()
515 .getMessage(OFType.FLOW_MOD);
516
517 OFActionOutput action = new OFActionOutput();
518 action.setMaxLength((short)0xffff);
519 List<OFAction> actions = new ArrayList<OFAction>();
520 actions.add(action);
521
522 fm.setIdleTimeout((short)0)
523 .setHardTimeout((short)0)
524 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
525 .setCookie(L2_FWD_COOKIE)
526 .setCommand(OFFlowMod.OFPFC_ADD)
527 //.setMatch(match)
528 .setActions(actions)
529 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
530
531 //Don't push the first flow entry. We need to push entries in the
532 //first switch based on IP prefix which we don't know yet.
533 for (int i = 1; i < flowEntries.size(); i++){
534 FlowEntry flowEntry = flowEntries.get(i);
535
536 OFMatch match = new OFMatch();
537 match.setDataLayerDestination(router.getRouterMac().toBytes());
538 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
539 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
540
541 fm.setMatch(match);
542
543 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
544
545 if (sw == null){
546 log.warn("Switch not found when pushing flow mod");
547 continue;
548 }
549
550 List<OFMessage> msglist = new ArrayList<OFMessage>();
551 msglist.add(fm);
552 try {
553 sw.write(msglist, null);
554 sw.flush();
555 } catch (IOException e) {
556 log.error("Failure writing flow mod", e);
557 }
558
559 try {
560 fm = fm.clone();
561 } catch (CloneNotSupportedException e1) {
562 log.error("Failure cloning flow mod", e1);
563 }
564 }
565 }
566
pingping-lina2cbfad2013-03-07 08:39:21 +0800567 @Override
568 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +0800569 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart61ba9372013-05-19 20:10:29 -0700570 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +0800571
Jonathan Hart61ba9372013-05-19 20:10:29 -0700572 //Retrieve the RIB from BGPd during startup
573 retrieveRib();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700574
575 //Don't have to do this as we'll never have switches connected here
576 //calculateFullMesh();
pingping-lina2cbfad2013-03-07 08:39:21 +0800577 }
578
579 @Override
580 public void topologyChanged() {
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700581 //Probably need to look at all changes, not just port changes
582 /*
pingping-lina2cbfad2013-03-07 08:39:21 +0800583 boolean change = false;
584 String changelog = "";
585
586 for (LDUpdate ldu : topology.getLastLinkUpdates()) {
587 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.PORT_DOWN)) {
588 change = true;
589 changelog = changelog + " down ";
590 } else if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.PORT_UP)) {
591 change = true;
592 changelog = changelog + " up ";
593 }
594 }
595 log.info ("received topo change" + changelog);
596
597 if (change) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700598 //RestClient.get ("http://localhost:5000/topo_change");
pingping-lina2cbfad2013-03-07 08:39:21 +0800599 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700600 */
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200601
602 for (LDUpdate update : topology.getLastLinkUpdates()){
603 log.debug("{} event causing internal L2 path recalculation",
604 update.getOperation().toString());
605
606 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700607 calculateFullMesh();
pingping-lina2cbfad2013-03-07 08:39:21 +0800608 }
609}