blob: c57d4d8e6e86f686b99c6f4d584c2b7cdfee2d55 [file] [log] [blame]
HIGUCHI Yutaea60e5f2013-06-12 11:10:21 -07001package net.onrc.onos.ofcontroller.bgproute;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
Jonathan Hartd1f23252013-06-13 15:17:05 +12003import java.io.File;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07004import java.io.IOException;
5import java.net.InetAddress;
Jonathan Hart61ba9372013-05-19 20:10:29 -07006import java.net.UnknownHostException;
pingping-lina2cbfad2013-03-07 08:39:21 +08007import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07008import java.util.Collection;
Jonathan Hart98957bf2013-07-01 14:49:24 +12009import java.util.Comparator;
pingping-lina2cbfad2013-03-07 08:39:21 +080010import java.util.HashMap;
Jonathan Hart98957bf2013-07-01 14:49:24 +120011import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070012import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070013import java.util.Map;
Jonathan Hart98957bf2013-07-01 14:49:24 +120014import java.util.concurrent.ConcurrentSkipListSet;
15import java.util.concurrent.Executors;
16import java.util.concurrent.ScheduledExecutorService;
17import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080018
Jonathan Hart61ba9372013-05-19 20:10:29 -070019import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070020import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120021import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080022import net.floodlightcontroller.core.module.FloodlightModuleContext;
23import net.floodlightcontroller.core.module.FloodlightModuleException;
24import net.floodlightcontroller.core.module.IFloodlightModule;
25import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120026import net.floodlightcontroller.core.util.SingletonTask;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070027import net.floodlightcontroller.devicemanager.IDeviceService;
28import net.floodlightcontroller.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120029import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080030import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120031import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080032import net.floodlightcontroller.topology.ITopologyListener;
33import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120034import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070035import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120036import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070037import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
38import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120039import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070040import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120041import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070042import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070043import net.onrc.onos.ofcontroller.util.Port;
44import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080045import net.sf.json.JSONArray;
46import net.sf.json.JSONObject;
47import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080048
Jonathan Hartd1f23252013-06-13 15:17:05 +120049import org.codehaus.jackson.JsonParseException;
50import org.codehaus.jackson.map.JsonMappingException;
51import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070052import org.openflow.protocol.OFFlowMod;
53import org.openflow.protocol.OFMatch;
54import org.openflow.protocol.OFMessage;
55import org.openflow.protocol.OFPacketOut;
56import org.openflow.protocol.OFType;
57import org.openflow.protocol.action.OFAction;
58import org.openflow.protocol.action.OFActionDataLayerDestination;
59import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120060import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080061import org.slf4j.Logger;
62import org.slf4j.LoggerFactory;
63
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070064import com.google.common.net.InetAddresses;
65
Jonathan Hart1236a9b2013-06-18 22:10:05 +120066public class BgpRoute implements IFloodlightModule, IBgpRouteService,
67 ITopologyListener, IOFSwitchListener {
pingping-lina2cbfad2013-03-07 08:39:21 +080068
69 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
70
71 protected IFloodlightProviderService floodlightProvider;
72 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070073 protected ITopoRouteService topoRouteService;
74 protected IDeviceService devices;
75 protected IRestApiService restApi;
76
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120077 protected ProxyArpManager proxyArp;
78
pingping-lina2cbfad2013-03-07 08:39:21 +080079 protected static Ptree ptree;
Jonathan Hart61ba9372013-05-19 20:10:29 -070080 protected String bgpdRestIp;
81 protected String routerId;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120082 protected String gatewaysFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070083
84 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
85 //the controller/OS should hand out cookie IDs to prevent conflicts.
86 protected final long APP_COOKIE = 0xa0000000000000L;
87 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
88 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
89 //Cookie for flows in ingress switches that rewrite the MAC address
90 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120091 //Cookie for flows that setup BGP paths
92 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +120093 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
94 //need to be higher priority than this otherwise the rewrite may not get done
95 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070096
Jonathan Hart832a7cb2013-06-24 11:25:35 +120097 protected final short BGP_PORT = 179;
98
Jonathan Hart98957bf2013-07-01 14:49:24 +120099 protected final int TOPO_DETECTION_WAIT = 2; //seconds
100
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200101 //Configuration stuff
Jonathan Hartd1f23252013-06-13 15:17:05 +1200102 protected Map<String, GatewayRouter> gatewayRouters;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200103 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200104 protected Map<String, Interface> interfaces;
105 protected List<BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200106 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200107
108 //True when all switches have connected
109 protected volatile boolean switchesConnected = false;
110 //True when we have a full mesh of shortest paths between gateways
111 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200112
113 //protected ConcurrentSkipListSet<LDUpdate> linkUpdates;
114 protected ArrayList<LDUpdate> linkUpdates;
115 protected SingletonTask topologyChangeDetectorTask;
116
117 //protected ILinkStorage linkStorage;//XXX
118
119 protected class TopologyChangeDetector implements Runnable {
120 @Override
121 public void run() {
122 log.debug("Running topology change detection task");
123 synchronized (linkUpdates) {
124 //This is the model the REST API uses to retrive network graph info
125 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
126
127 List<Link> activeLinks = topoLinkService.getActiveLinks();
128 for (Link l : activeLinks){
129 log.debug("active link: {}", l);
130 }
131
132 Iterator<LDUpdate> it = linkUpdates.iterator();
133 while (it.hasNext()){
134 LDUpdate ldu = it.next();
135 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
136 ldu.getDst(), ldu.getDstPort());
137
138 if (activeLinks.contains(l)){
139 log.debug("Not found: {}", l);
140 it.remove();
141 }
142 }
143 }
144
145 if (linkUpdates.isEmpty()){
146 //All updates have been seen in network map.
147 //We can check if topology is ready
148 log.debug("No know changes outstanding. Checking topology now");
149 checkStatus();
150 }
151 else {
152 //We know of some link updates that haven't propagated to the database yet
153 log.debug("Some changes not found in network map- size {}", linkUpdates.size());
154 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
155 }
156 }
157 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700158
Jonathan Hartd1f23252013-06-13 15:17:05 +1200159 private void readGatewaysConfiguration(String gatewaysFilename){
160 File gatewaysFile = new File(gatewaysFilename);
161 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700162
Jonathan Hartd1f23252013-06-13 15:17:05 +1200163 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200164 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
165
166 gatewayRouters = config.getGateways();
167 switches = config.getSwitches();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200168 interfaces = config.getInterfaces();
169 bgpPeers = config.getPeers();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200170
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200171 bgpdAttachmentPoint = new SwitchPort(
172 new Dpid(config.getBgpdAttachmentDpid()),
173 new Port(config.getBgpdAttachmentPort()));
174 //bgpdAttachmentDpid = config.getBgpdAttachmentDpid();
175 //bgpdAttachmentPort = config.getBgpdAttachmentPort();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200176
Jonathan Hartd1f23252013-06-13 15:17:05 +1200177 } catch (JsonParseException e) {
178 log.error("Error in JSON file", e);
179 System.exit(1);
180 } catch (JsonMappingException e) {
181 log.error("Error in JSON file", e);
182 System.exit(1);
183 } catch (IOException e) {
184 log.error("Error reading JSON file", e);
185 System.exit(1);
186 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700187 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800188
189 @Override
190 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700191 Collection<Class<? extends IFloodlightService>> l
192 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800193 l.add(IBgpRouteService.class);
194 return l;
195 }
196
197 @Override
198 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700199 Map<Class<? extends IFloodlightService>, IFloodlightService> m
200 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800201 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800202 return m;
203 }
204
pingping-lina2cbfad2013-03-07 08:39:21 +0800205 @Override
206 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700207 Collection<Class<? extends IFloodlightService>> l
208 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800209 l.add(IFloodlightProviderService.class);
210 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700211 l.add(ITopoRouteService.class);
212 l.add(IDeviceService.class);
213 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800214 return l;
215 }
216
217 @Override
218 public void init(FloodlightModuleContext context)
219 throws FloodlightModuleException {
220
221 ptree = new Ptree(32);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700222
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200223 //routerIpAddresses = new HashSet<InetAddress>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800224
225 // Register floodlight provider and REST handler.
226 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800227 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700228 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
229 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200230 restApi = context.getServiceImpl(IRestApiService.class);
231
232 //TODO We'll initialise this here for now, but it should really be done as
233 //part of the controller core
234 proxyArp = new ProxyArpManager(floodlightProvider, topology);
pingping-lina2cbfad2013-03-07 08:39:21 +0800235
Jonathan Hart98957bf2013-07-01 14:49:24 +1200236 /*
237 linkStorage = new LinkStorageImpl();
238 //XXX Hack to pull out the database location from NetworkGraphPublisher's config
239 String databaseConfig = null;
240 for (IFloodlightModule fm : context.getAllModules()){
241 if (fm instanceof NetworkGraphPublisher){
242 Map<String, String> configMap = context.getConfigParams(fm);
243 databaseConfig = configMap.get("dbconf");
244 break;
245 }
246 }
247 if (databaseConfig == null){
248 log.error("Couldn't find database config string \"dbconf\"");
249 System.exit(1);
250 }
251 linkStorage.init(databaseConfig);
252 */
253 //linkUpdates = new ConcurrentSkipListSet<ILinkDiscovery.LDUpdate>();
254 linkUpdates = new ArrayList<LDUpdate>();
255 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
256 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
257
Jonathan Hart61ba9372013-05-19 20:10:29 -0700258 //Read in config values
259 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
260 if (bgpdRestIp == null){
261 log.error("BgpdRestIp property not found in config file");
262 System.exit(1);
263 }
264 else {
265 log.info("BgpdRestIp set to {}", bgpdRestIp);
266 }
267
268 routerId = context.getConfigParams(this).get("RouterId");
269 if (routerId == null){
270 log.error("RouterId property not found in config file");
271 System.exit(1);
272 }
273 else {
274 log.info("RouterId set to {}", routerId);
275 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200276
277 readGatewaysConfiguration(gatewaysFilename);
pingping-lina2cbfad2013-03-07 08:39:21 +0800278 // Test.
279 //test();
280 }
281
282 public Ptree getPtree() {
283 return ptree;
284 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700285
286 public void clearPtree() {
287 //ptree = null;
288 ptree = new Ptree(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800289 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700290
pingping-line2a09ca2013-03-23 09:33:58 +0800291 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700292 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800293 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700294
pingping-line2a09ca2013-03-23 09:33:58 +0800295 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700296 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800297 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800298
299 // Return nexthop address as byte array.
300 public Rib lookupRib(byte[] dest) {
301 if (ptree == null) {
302 log.debug("lookupRib: ptree null");
303 return null;
304 }
305
306 PtreeNode node = ptree.match(dest, 32);
307 if (node == null) {
308 log.debug("lookupRib: ptree node null");
309 return null;
310 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700311
pingping-lina2cbfad2013-03-07 08:39:21 +0800312 if (node.rib == null) {
313 log.debug("lookupRib: ptree rib null");
314 return null;
315 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700316
pingping-lina2cbfad2013-03-07 08:39:21 +0800317 ptree.delReference(node);
318
319 return node.rib;
320 }
321
Jonathan Hart61ba9372013-05-19 20:10:29 -0700322 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800323 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700324 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800325 System.out.println("Here it is");
326 Prefix p = new Prefix("128.0.0.0", 8);
327 Prefix q = new Prefix("8.0.0.0", 8);
328 Prefix r = new Prefix("10.0.0.0", 24);
329 Prefix a = new Prefix("10.0.0.1", 32);
330
331 ptree.acquire(p.getAddress(), p.masklen);
332 ptree.acquire(q.getAddress(), q.masklen);
333 ptree.acquire(r.getAddress(), r.masklen);
334
335 System.out.println("Traverse start");
336 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
337 Prefix p_result = new Prefix(node.key, node.keyBits);
338 }
339
340 PtreeNode n = ptree.match(a.getAddress(), a.masklen);
341 if (n != null) {
342 System.out.println("Matched prefix for 10.0.0.1:");
343 Prefix x = new Prefix(n.key, n.keyBits);
344 ptree.delReference(n);
345 }
346
347 n = ptree.lookup(p.getAddress(), p.masklen);
348 if (n != null) {
349 ptree.delReference(n);
350 ptree.delReference(n);
351 }
352 System.out.println("Traverse start");
353 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
354 Prefix p_result = new Prefix(node.key, node.keyBits);
355 }
356
357 n = ptree.lookup(q.getAddress(), q.masklen);
358 if (n != null) {
359 ptree.delReference(n);
360 ptree.delReference(n);
361 }
362 System.out.println("Traverse start");
363 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
364 Prefix p_result = new Prefix(node.key, node.keyBits);
365 }
366
367 n = ptree.lookup(r.getAddress(), r.masklen);
368 if (n != null) {
369 ptree.delReference(n);
370 ptree.delReference(n);
371 }
372 System.out.println("Traverse start");
373 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
374 Prefix p_result = new Prefix(node.key, node.keyBits);
375 }
376
377 }
378
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200379 private String getPrefixFromPtree(PtreeNode node){
380 InetAddress address = null;
381 try {
382 address = InetAddress.getByAddress(node.key);
383 } catch (UnknownHostException e1) {
384 //Should never happen is the reverse conversion has already been done
385 log.error("Malformed IP address");
386 return "";
387 }
388 return address.toString() + "/" + node.rib.masklen;
389 }
390
Jonathan Hart61ba9372013-05-19 20:10:29 -0700391 private void retrieveRib(){
392 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
393 String response = RestClient.get(url);
394
395 if (response.equals("")){
396 return;
397 }
398
399 response = response.replaceAll("\"", "'");
400 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
401 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
402 String router_id = jsonObj.getString("router-id");
403
404 int size = rib_json_array.size();
405
406 log.info("Retrived RIB of {} entries from BGPd", size);
407
408 for (int j = 0; j < size; j++) {
409 JSONObject second_json_object = rib_json_array.getJSONObject(j);
410 String prefix = second_json_object.getString("prefix");
411 String nexthop = second_json_object.getString("nexthop");
412
413 //insert each rib entry into the local rib;
414 String[] substring = prefix.split("/");
415 String prefix1 = substring[0];
416 String mask1 = substring[1];
417
418 Prefix p;
419 try {
420 p = new Prefix(prefix1, Integer.valueOf(mask1));
421 } catch (NumberFormatException e) {
422 log.warn("Wrong mask format in RIB JSON: {}", mask1);
423 continue;
424 } catch (UnknownHostException e1) {
425 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
426 continue;
427 }
428
429 PtreeNode node = ptree.acquire(p.getAddress(), p.masklen);
430 Rib rib = new Rib(router_id, nexthop, p.masklen);
431
432 if (node.rib != null) {
433 node.rib = null;
434 ptree.delReference(node);
435 }
436
437 node.rib = rib;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700438
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200439 prefixAdded(node);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700440 }
441 }
442
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200443 public void prefixAdded(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200444 if (!topologyReady){
445 return;
446 }
447
448 String prefix = getPrefixFromPtree(node);
449
450 log.debug("New prefix {} added, next hop {}",
451 prefix, node.rib.nextHop.toString());
452
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700453 //Add a flow to rewrite mac for this prefix to all border switches
Jonathan Hartd1f23252013-06-13 15:17:05 +1200454 GatewayRouter thisRouter = gatewayRouters
455 .get(InetAddresses.toAddrString(node.rib.nextHop));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700456
457 if (thisRouter == null){
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200458 //TODO local router isn't in gateway list so this will get thrown
459 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
460 log.error("Couldn't find next hop router in router {} in config"
461 , node.rib.nextHop.toString());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700462 return; //just quit out here? This is probably a configuration error
463 }
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200464
Jonathan Hartd1f23252013-06-13 15:17:05 +1200465 for (GatewayRouter ingressRouter : gatewayRouters.values()){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700466 if (ingressRouter == thisRouter) {
467 continue;
468 }
469
470 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200471 ingressRouter.getAttachmentPoint(),
472 thisRouter.getAttachmentPoint());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700473
474 if (shortestPath == null){
475 log.debug("Shortest path between {} and {} not found",
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200476 ingressRouter.getAttachmentPoint(),
477 thisRouter.getAttachmentPoint());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700478 return; // just quit here?
479 }
480
481 //TODO check the shortest path against the cached version we
482 //calculated before. If they don't match up that's a problem
483
484 //Set up the flow mod
485 OFFlowMod fm =
486 (OFFlowMod) floodlightProvider.getOFMessageFactory()
487 .getMessage(OFType.FLOW_MOD);
488
489 fm.setIdleTimeout((short)0)
490 .setHardTimeout((short)0)
491 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
492 .setCookie(MAC_RW_COOKIE)
493 .setCommand(OFFlowMod.OFPFC_ADD)
494 //.setMatch(match)
495 //.setActions(actions)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200496 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700497 .setLengthU(OFFlowMod.MINIMUM_LENGTH
498 + OFActionDataLayerDestination.MINIMUM_LENGTH
499 + OFActionOutput.MINIMUM_LENGTH);
500
501 OFMatch match = new OFMatch();
502 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200503 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700504
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200505 match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
506 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200507
508 InetAddress address = null;
509 try {
510 address = InetAddress.getByAddress(node.key);
511 } catch (UnknownHostException e1) {
512 //Should never happen is the reverse conversion has already been done
513 log.error("Malformed IP address");
514 return;
515 }
516
517 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
518 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700519
520 //Set up MAC rewrite action
521 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
522 macRewriteAction.setDataLayerAddress(thisRouter.getRouterMac().toBytes());
523
524 //Set up output action
525 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200526 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700527
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200528 Port outputPort = shortestPath.flowEntries().get(0).outPort();
529 outputAction.setPort(outputPort.value());
530
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700531 List<OFAction> actions = new ArrayList<OFAction>();
532 actions.add(macRewriteAction);
533 actions.add(outputAction);
534 fm.setActions(actions);
535
536 //Write to switch
537 IOFSwitch sw = floodlightProvider.getSwitches()
538 .get(ingressRouter.getAttachmentPoint().dpid().value());
539
540 if (sw == null){
541 log.warn("Switch not found when pushing flow mod");
542 continue;
543 }
544
545 List<OFMessage> msglist = new ArrayList<OFMessage>();
546 msglist.add(fm);
547 try {
548 sw.write(msglist, null);
549 sw.flush();
550 } catch (IOException e) {
551 log.error("Failure writing flow mod", e);
552 }
553 }
554 }
555
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200556 public void prefixDeleted(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200557 if (!topologyReady) {
558 return;
559 }
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200560
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200561 String prefix = getPrefixFromPtree(node);
562
563 log.debug("Prefix {} deleted, next hop {}",
564 prefix, node.rib.nextHop.toString());
565
566 //Remove MAC rewriting flows from other border switches
567 GatewayRouter thisRouter = gatewayRouters
568 .get(InetAddresses.toAddrString(node.rib.nextHop));
569
570 for (GatewayRouter ingressRouter : gatewayRouters.values()){
571 if (ingressRouter == thisRouter) {
572 continue;
573 }
574
575 //Set up the flow mod
576 OFFlowMod fm =
577 (OFFlowMod) floodlightProvider.getOFMessageFactory()
578 .getMessage(OFType.FLOW_MOD);
579
580 fm.setIdleTimeout((short)0)
581 .setHardTimeout((short)0)
582 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
583 .setCookie(MAC_RW_COOKIE)
584 .setCommand(OFFlowMod.OFPFC_DELETE)
585 //.setMatch(match)
586 //.setActions(actions)
587 .setPriority(SDNIP_PRIORITY)
588 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
589 //+ OFActionDataLayerDestination.MINIMUM_LENGTH
590 //+ OFActionOutput.MINIMUM_LENGTH);
591
592 OFMatch match = new OFMatch();
593 match.setDataLayerType(Ethernet.TYPE_IPv4);
594 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
595
596 match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
597 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
598
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200599 InetAddress address = null;
600 try {
601 address = InetAddress.getByAddress(node.key);
602 } catch (UnknownHostException e1) {
603 //Should never happen is the reverse conversion has already been done
604 log.error("Malformed IP address");
605 return;
606 }
607
608 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
609 fm.setMatch(match);
610
611 //Write to switch
612 IOFSwitch sw = floodlightProvider.getSwitches()
613 .get(ingressRouter.getAttachmentPoint().dpid().value());
614
615 if (sw == null){
616 log.warn("Switch not found when pushing flow mod");
617 continue;
618 }
619
620 List<OFMessage> msglist = new ArrayList<OFMessage>();
621 msglist.add(fm);
622 try {
623 sw.write(msglist, null);
624 sw.flush();
625 } catch (IOException e) {
626 log.error("Failure writing flow mod", e);
627 }
628 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700629 }
630
631 /*
632 * On startup we need to calculate a full mesh of paths between all gateway
633 * switches
634 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200635 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700636 Map<IOFSwitch, SwitchPort> gatewaySwitches = new HashMap<IOFSwitch, SwitchPort>();
637
638 //have to account for switches not being there, paths not being found.
639
Jonathan Hartd1f23252013-06-13 15:17:05 +1200640 for (GatewayRouter router : gatewayRouters.values()){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700641 SwitchPort switchPort = router.getAttachmentPoint();
642
643 IOFSwitch sw = floodlightProvider.getSwitches().get(switchPort.dpid().value());
644
645 if (sw == null){
646 log.debug("Gateway switch {} not here yet", switchPort.dpid().value());
647 return; // just quit here?
648 }
649
650 //Only need to know 1 external-facing port from each gateway switch
651 //which we can feed into shortest path calculation
652 if (!gatewaySwitches.containsKey(sw)){
653 gatewaySwitches.put(sw, switchPort);
654 }
655
656 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700657
658 //For each border router, calculate and install a path from every other
659 //border switch to said border router. However, don't install the entry
660 //in to the first hop switch, as we need to install an entry to rewrite
661 //for each prefix received. This will be done later when prefixes have
662 //actually been received.
663
Jonathan Hartd1f23252013-06-13 15:17:05 +1200664 for (GatewayRouter dstRouter : gatewayRouters.values()){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700665 SwitchPort routerAttachmentPoint = dstRouter.getAttachmentPoint();
666 for (Map.Entry<IOFSwitch, SwitchPort> src : gatewaySwitches.entrySet()) {
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700667
668 if (routerAttachmentPoint.dpid().value() ==
669 src.getKey().getId()){
670 continue;
671 }
672
673 DataPath shortestPath = topoRouteService.getShortestPath(
674 src.getValue(), routerAttachmentPoint);
675
676 if (shortestPath == null){
677 log.debug("Shortest path between {} and {} not found",
678 src.getValue(), routerAttachmentPoint);
679 return; // just quit here?
680 }
681
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700682 //install flows
683 installPath(shortestPath.flowEntries(), dstRouter);
684 }
685 }
686 }
687
688 private void installPath(List<FlowEntry> flowEntries, GatewayRouter router){
689
690 //Set up the flow mod
691 OFFlowMod fm =
692 (OFFlowMod) floodlightProvider.getOFMessageFactory()
693 .getMessage(OFType.FLOW_MOD);
694
695 OFActionOutput action = new OFActionOutput();
696 action.setMaxLength((short)0xffff);
697 List<OFAction> actions = new ArrayList<OFAction>();
698 actions.add(action);
699
700 fm.setIdleTimeout((short)0)
701 .setHardTimeout((short)0)
702 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
703 .setCookie(L2_FWD_COOKIE)
704 .setCommand(OFFlowMod.OFPFC_ADD)
705 //.setMatch(match)
706 .setActions(actions)
707 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
708
709 //Don't push the first flow entry. We need to push entries in the
710 //first switch based on IP prefix which we don't know yet.
711 for (int i = 1; i < flowEntries.size(); i++){
712 FlowEntry flowEntry = flowEntries.get(i);
713
714 OFMatch match = new OFMatch();
715 match.setDataLayerDestination(router.getRouterMac().toBytes());
716 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
717 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
718
719 fm.setMatch(match);
720
721 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
722
723 if (sw == null){
724 log.warn("Switch not found when pushing flow mod");
725 continue;
726 }
727
728 List<OFMessage> msglist = new ArrayList<OFMessage>();
729 msglist.add(fm);
730 try {
731 sw.write(msglist, null);
732 sw.flush();
733 } catch (IOException e) {
734 log.error("Failure writing flow mod", e);
735 }
736
737 try {
738 fm = fm.clone();
739 } catch (CloneNotSupportedException e1) {
740 log.error("Failure cloning flow mod", e1);
741 }
742 }
743 }
744
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200745 private void setupBgpPaths(){
746 for (BgpPeer bgpPeer : bgpPeers){
747 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
748
749 DataPath path = topoRouteService.getShortestPath(
750 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
751
752 if (path == null){
753 log.debug("Unable to compute path for BGP traffic for {}",
754 bgpPeer.getIpAddress());
755 continue;
756 }
757
758 //Set up the flow mod
759 OFFlowMod fm =
760 (OFFlowMod) floodlightProvider.getOFMessageFactory()
761 .getMessage(OFType.FLOW_MOD);
762
763 OFActionOutput action = new OFActionOutput();
764 action.setMaxLength((short)0xffff);
765 List<OFAction> actions = new ArrayList<OFAction>();
766 actions.add(action);
767
768 fm.setIdleTimeout((short)0)
769 .setHardTimeout((short)0)
770 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
771 .setCookie(BGP_COOKIE)
772 .setCommand(OFFlowMod.OFPFC_ADD)
773 .setPriority(SDNIP_PRIORITY)
774 .setActions(actions)
775 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
776
777 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
778 OFMatch forwardMatchSrc = new OFMatch();
779
780
781 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
782 + "/32";
783 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
784 + "/32";
785
786 //Common match fields
787 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
788 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
789 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
790 forwardMatchSrc.setTransportDestination(BGP_PORT);
791 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
792 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
793
794
795 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
796
797 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
798 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
799
800 OFMatch forwardMatchDst = forwardMatchSrc.clone();
801
802 forwardMatchSrc.setTransportSource(BGP_PORT);
803 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
804 forwardMatchDst.setTransportDestination(BGP_PORT);
805 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
806
807 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
808 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
809
810 OFMatch reverseMatchDst = reverseMatchSrc.clone();
811
812 reverseMatchSrc.setTransportSource(BGP_PORT);
813 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
814 reverseMatchDst.setTransportDestination(BGP_PORT);
815 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
816
817 fm.setMatch(forwardMatchSrc);
818
819 for (FlowEntry flowEntry : path.flowEntries()){
820 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
821 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
822 try {
823 forwardFlowModSrc = fm.clone();
824 forwardFlowModDst = fm.clone();
825 reverseFlowModSrc = fm.clone();
826 reverseFlowModDst = fm.clone();
827 } catch (CloneNotSupportedException e) {
828 log.warn("Clone failed", e);
829 continue;
830 }
831
832 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
833 forwardFlowModSrc.setMatch(forwardMatchSrc);
834 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
835 .setPort(flowEntry.outPort().value());
836
837 forwardMatchDst.setInputPort(flowEntry.inPort().value());
838 forwardFlowModDst.setMatch(forwardMatchDst);
839 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
840 .setPort(flowEntry.outPort().value());
841
842 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
843 reverseFlowModSrc.setMatch(reverseMatchSrc);
844 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
845 .setPort(flowEntry.inPort().value());
846
847 reverseMatchDst.setInputPort(flowEntry.outPort().value());
848 reverseFlowModDst.setMatch(reverseMatchDst);
849 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
850 .setPort(flowEntry.inPort().value());
851
852 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
853
854 //Hopefully the switch is there
855 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
856 msgList.add(forwardFlowModSrc);
857 msgList.add(forwardFlowModDst);
858 msgList.add(reverseFlowModSrc);
859 msgList.add(reverseFlowModDst);
860
861 try {
862 sw.write(msgList, null);
863 sw.flush();
864 } catch (IOException e) {
865 log.error("Failure writing flow mod", e);
866 }
867 }
868 }
869 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200870
871 private void beginRouting(){
872 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200873 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200874 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200875
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200876 //Traverse ptree and create flows for all routes
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200877 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
878 if (node.rib != null){
879 prefixAdded(node);
880 }
881 }
882 }
883
884 private void checkSwitchesConnected(){
885 for (String dpid : switches){
886 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
887 log.debug("Not all switches are here yet");
888 return;
889 }
890 }
891 switchesConnected = true;
892 }
893
894 private void checkTopologyReady(){
895 for (GatewayRouter dstRouter : gatewayRouters.values()){
896 SwitchPort dstAttachmentPoint = dstRouter.getAttachmentPoint();
897 for (GatewayRouter srcRouter : gatewayRouters.values()) {
898
899 if (dstRouter == srcRouter){
900 continue;
901 }
902
903 SwitchPort srcAttachmentPoint = srcRouter.getAttachmentPoint();
904
905 DataPath shortestPath = topoRouteService.getShortestPath(
906 srcAttachmentPoint, dstAttachmentPoint);
907
908 if (shortestPath == null){
909 log.debug("Shortest path between {} and {} not found",
910 srcAttachmentPoint, dstAttachmentPoint);
911 return;
912 }
913 }
914 }
915 topologyReady = true;
916 }
917
918 private void checkStatus(){
919 log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
920
921 if (!switchesConnected){
922 checkSwitchesConnected();
923 }
924 boolean oldTopologyReadyStatus = topologyReady;
925 if (switchesConnected && !topologyReady){
926 checkTopologyReady();
927 }
928 if (!oldTopologyReadyStatus && topologyReady){
929 beginRouting();
930 }
931 }
932
pingping-lina2cbfad2013-03-07 08:39:21 +0800933 @Override
934 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +0800935 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200936 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700937 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +0800938
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200939 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
940
Jonathan Hart61ba9372013-05-19 20:10:29 -0700941 //Retrieve the RIB from BGPd during startup
942 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800943 }
944
945 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200946 public void topologyChanged() {
947 //There seems to be more topology events than there should be. Lots of link
948 //updated, port up and switch updated on what should be a fairly static topology
pingping-lina2cbfad2013-03-07 08:39:21 +0800949
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200950 boolean refreshNeeded = false;
951 for (LDUpdate ldu : topology.getLastLinkUpdates()){
952 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
953 //We don't need to recalculate anything for just link updates
954 //They happen way too frequently (may be a bug in our link discovery)
955 refreshNeeded = true;
956 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200957
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200958 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200959 /*
960 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
961 log.debug("Link Added: src={} outPort={} dst={} inPort={}",
962 new Object[] {
963 HexString.toHexString(ldu.getSrc()), ldu.getSrcPort(),
964 HexString.toHexString(ldu.getDst()), ldu.getDstPort()});
965 TopoLinkServiceImpl impl = new TopoLinkServiceImpl();
966
967 List<Link> retval = impl.getActiveLinks();
968
969 log.debug("retval size {}", retval.size());
970
971 for (Link l : retval){
972 log.debug("link {}", l);
973 }
974 }
975 */
976 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
977 synchronized (linkUpdates) {
978 linkUpdates.add(ldu);
979 }
980 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200981 }
982
983 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200984 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
985 /*if (topologyReady){
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200986 setupFullMesh();
987 }
988 else{
989 checkStatus();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200990 }*/
991
pingping-lina2cbfad2013-03-07 08:39:21 +0800992 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200993 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800994
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200995 //TODO determine whether we need to listen for switch joins
996 @Override
997 public void addedSwitch(IOFSwitch sw) {
998 //checkStatus();
999 }
1000
1001 @Override
1002 public void removedSwitch(IOFSwitch sw) {
1003 // TODO Auto-generated method stub
1004 }
1005
1006 @Override
1007 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001008
1009 @Override
1010 public String getName() {
1011 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +08001012 }
1013}