blob: 570b84704c59bc80c95cad8698f5e004325e5567 [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;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070040import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070041import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120042import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070043import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070044import net.onrc.onos.ofcontroller.util.Port;
45import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080046import net.sf.json.JSONArray;
47import net.sf.json.JSONObject;
48import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080049
Jonathan Hartd1f23252013-06-13 15:17:05 +120050import org.codehaus.jackson.JsonParseException;
51import org.codehaus.jackson.map.JsonMappingException;
52import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070053import org.openflow.protocol.OFFlowMod;
54import org.openflow.protocol.OFMatch;
55import org.openflow.protocol.OFMessage;
56import org.openflow.protocol.OFPacketOut;
57import org.openflow.protocol.OFType;
58import org.openflow.protocol.action.OFAction;
59import org.openflow.protocol.action.OFActionDataLayerDestination;
60import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120061import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080062import org.slf4j.Logger;
63import org.slf4j.LoggerFactory;
64
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070065import com.google.common.net.InetAddresses;
66
Jonathan Hart1236a9b2013-06-18 22:10:05 +120067public class BgpRoute implements IFloodlightModule, IBgpRouteService,
68 ITopologyListener, IOFSwitchListener {
pingping-lina2cbfad2013-03-07 08:39:21 +080069
70 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
71
72 protected IFloodlightProviderService floodlightProvider;
73 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070074 protected ITopoRouteService topoRouteService;
75 protected IDeviceService devices;
76 protected IRestApiService restApi;
77
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120078 protected ProxyArpManager proxyArp;
79
pingping-lina2cbfad2013-03-07 08:39:21 +080080 protected static Ptree ptree;
Jonathan Hart61ba9372013-05-19 20:10:29 -070081 protected String bgpdRestIp;
82 protected String routerId;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120083 protected String gatewaysFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070084
85 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
86 //the controller/OS should hand out cookie IDs to prevent conflicts.
87 protected final long APP_COOKIE = 0xa0000000000000L;
88 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
89 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
90 //Cookie for flows in ingress switches that rewrite the MAC address
91 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120092 //Cookie for flows that setup BGP paths
93 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +120094 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
95 //need to be higher priority than this otherwise the rewrite may not get done
96 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070097
Jonathan Hart832a7cb2013-06-24 11:25:35 +120098 protected final short BGP_PORT = 179;
99
Jonathan Hart98957bf2013-07-01 14:49:24 +1200100 protected final int TOPO_DETECTION_WAIT = 2; //seconds
101
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200102 //Configuration stuff
Jonathan Hartd1f23252013-06-13 15:17:05 +1200103 protected Map<String, GatewayRouter> gatewayRouters;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200104 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200105 protected Map<String, Interface> interfaces;
106 protected List<BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200107 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200108
109 //True when all switches have connected
110 protected volatile boolean switchesConnected = false;
111 //True when we have a full mesh of shortest paths between gateways
112 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200113
114 //protected ConcurrentSkipListSet<LDUpdate> linkUpdates;
115 protected ArrayList<LDUpdate> linkUpdates;
116 protected SingletonTask topologyChangeDetectorTask;
117
118 //protected ILinkStorage linkStorage;//XXX
119
120 protected class TopologyChangeDetector implements Runnable {
121 @Override
122 public void run() {
123 log.debug("Running topology change detection task");
124 synchronized (linkUpdates) {
125 //This is the model the REST API uses to retrive network graph info
126 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
127
128 List<Link> activeLinks = topoLinkService.getActiveLinks();
129 for (Link l : activeLinks){
130 log.debug("active link: {}", l);
131 }
132
133 Iterator<LDUpdate> it = linkUpdates.iterator();
134 while (it.hasNext()){
135 LDUpdate ldu = it.next();
136 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
137 ldu.getDst(), ldu.getDstPort());
138
139 if (activeLinks.contains(l)){
140 log.debug("Not found: {}", l);
141 it.remove();
142 }
143 }
144 }
145
146 if (linkUpdates.isEmpty()){
147 //All updates have been seen in network map.
148 //We can check if topology is ready
149 log.debug("No know changes outstanding. Checking topology now");
150 checkStatus();
151 }
152 else {
153 //We know of some link updates that haven't propagated to the database yet
154 log.debug("Some changes not found in network map- size {}", linkUpdates.size());
155 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
156 }
157 }
158 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700159
Jonathan Hartd1f23252013-06-13 15:17:05 +1200160 private void readGatewaysConfiguration(String gatewaysFilename){
161 File gatewaysFile = new File(gatewaysFilename);
162 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700163
Jonathan Hartd1f23252013-06-13 15:17:05 +1200164 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200165 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
166
167 gatewayRouters = config.getGateways();
168 switches = config.getSwitches();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200169 interfaces = config.getInterfaces();
170 bgpPeers = config.getPeers();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200171
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200172 bgpdAttachmentPoint = new SwitchPort(
173 new Dpid(config.getBgpdAttachmentDpid()),
174 new Port(config.getBgpdAttachmentPort()));
175 //bgpdAttachmentDpid = config.getBgpdAttachmentDpid();
176 //bgpdAttachmentPort = config.getBgpdAttachmentPort();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200177
Jonathan Hartd1f23252013-06-13 15:17:05 +1200178 } catch (JsonParseException e) {
179 log.error("Error in JSON file", e);
180 System.exit(1);
181 } catch (JsonMappingException e) {
182 log.error("Error in JSON file", e);
183 System.exit(1);
184 } catch (IOException e) {
185 log.error("Error reading JSON file", e);
186 System.exit(1);
187 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700188 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800189
190 @Override
191 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700192 Collection<Class<? extends IFloodlightService>> l
193 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800194 l.add(IBgpRouteService.class);
195 return l;
196 }
197
198 @Override
199 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700200 Map<Class<? extends IFloodlightService>, IFloodlightService> m
201 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800202 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800203 return m;
204 }
205
pingping-lina2cbfad2013-03-07 08:39:21 +0800206 @Override
207 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700208 Collection<Class<? extends IFloodlightService>> l
209 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800210 l.add(IFloodlightProviderService.class);
211 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700212 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 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200229 restApi = context.getServiceImpl(IRestApiService.class);
230
231 //TODO We'll initialise this here for now, but it should really be done as
232 //part of the controller core
233 proxyArp = new ProxyArpManager(floodlightProvider, topology);
pingping-lina2cbfad2013-03-07 08:39:21 +0800234
Jonathan Hart98957bf2013-07-01 14:49:24 +1200235 /*
236 linkStorage = new LinkStorageImpl();
237 //XXX Hack to pull out the database location from NetworkGraphPublisher's config
238 String databaseConfig = null;
239 for (IFloodlightModule fm : context.getAllModules()){
240 if (fm instanceof NetworkGraphPublisher){
241 Map<String, String> configMap = context.getConfigParams(fm);
242 databaseConfig = configMap.get("dbconf");
243 break;
244 }
245 }
246 if (databaseConfig == null){
247 log.error("Couldn't find database config string \"dbconf\"");
248 System.exit(1);
249 }
250 linkStorage.init(databaseConfig);
251 */
252 //linkUpdates = new ConcurrentSkipListSet<ILinkDiscovery.LDUpdate>();
253 linkUpdates = new ArrayList<LDUpdate>();
254 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
255 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700256
257 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200258
Jonathan Hart61ba9372013-05-19 20:10:29 -0700259 //Read in config values
260 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
261 if (bgpdRestIp == null){
262 log.error("BgpdRestIp property not found in config file");
263 System.exit(1);
264 }
265 else {
266 log.info("BgpdRestIp set to {}", bgpdRestIp);
267 }
268
269 routerId = context.getConfigParams(this).get("RouterId");
270 if (routerId == null){
271 log.error("RouterId property not found in config file");
272 System.exit(1);
273 }
274 else {
275 log.info("RouterId set to {}", routerId);
276 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200277
278 readGatewaysConfiguration(gatewaysFilename);
pingping-lina2cbfad2013-03-07 08:39:21 +0800279 // Test.
280 //test();
281 }
282
283 public Ptree getPtree() {
284 return ptree;
285 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700286
287 public void clearPtree() {
288 //ptree = null;
289 ptree = new Ptree(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800290 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700291
pingping-line2a09ca2013-03-23 09:33:58 +0800292 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700293 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800294 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700295
pingping-line2a09ca2013-03-23 09:33:58 +0800296 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700297 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800298 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800299
300 // Return nexthop address as byte array.
301 public Rib lookupRib(byte[] dest) {
302 if (ptree == null) {
303 log.debug("lookupRib: ptree null");
304 return null;
305 }
306
307 PtreeNode node = ptree.match(dest, 32);
308 if (node == null) {
309 log.debug("lookupRib: ptree node null");
310 return null;
311 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700312
pingping-lina2cbfad2013-03-07 08:39:21 +0800313 if (node.rib == null) {
314 log.debug("lookupRib: ptree rib null");
315 return null;
316 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700317
pingping-lina2cbfad2013-03-07 08:39:21 +0800318 ptree.delReference(node);
319
320 return node.rib;
321 }
322
Jonathan Hart61ba9372013-05-19 20:10:29 -0700323 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800324 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700325 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800326 System.out.println("Here it is");
327 Prefix p = new Prefix("128.0.0.0", 8);
328 Prefix q = new Prefix("8.0.0.0", 8);
329 Prefix r = new Prefix("10.0.0.0", 24);
330 Prefix a = new Prefix("10.0.0.1", 32);
331
332 ptree.acquire(p.getAddress(), p.masklen);
333 ptree.acquire(q.getAddress(), q.masklen);
334 ptree.acquire(r.getAddress(), r.masklen);
335
336 System.out.println("Traverse start");
337 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
338 Prefix p_result = new Prefix(node.key, node.keyBits);
339 }
340
341 PtreeNode n = ptree.match(a.getAddress(), a.masklen);
342 if (n != null) {
343 System.out.println("Matched prefix for 10.0.0.1:");
344 Prefix x = new Prefix(n.key, n.keyBits);
345 ptree.delReference(n);
346 }
347
348 n = ptree.lookup(p.getAddress(), p.masklen);
349 if (n != null) {
350 ptree.delReference(n);
351 ptree.delReference(n);
352 }
353 System.out.println("Traverse start");
354 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
355 Prefix p_result = new Prefix(node.key, node.keyBits);
356 }
357
358 n = ptree.lookup(q.getAddress(), q.masklen);
359 if (n != null) {
360 ptree.delReference(n);
361 ptree.delReference(n);
362 }
363 System.out.println("Traverse start");
364 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
365 Prefix p_result = new Prefix(node.key, node.keyBits);
366 }
367
368 n = ptree.lookup(r.getAddress(), r.masklen);
369 if (n != null) {
370 ptree.delReference(n);
371 ptree.delReference(n);
372 }
373 System.out.println("Traverse start");
374 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
375 Prefix p_result = new Prefix(node.key, node.keyBits);
376 }
377
378 }
379
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200380 private String getPrefixFromPtree(PtreeNode node){
381 InetAddress address = null;
382 try {
383 address = InetAddress.getByAddress(node.key);
384 } catch (UnknownHostException e1) {
385 //Should never happen is the reverse conversion has already been done
386 log.error("Malformed IP address");
387 return "";
388 }
389 return address.toString() + "/" + node.rib.masklen;
390 }
391
Jonathan Hart61ba9372013-05-19 20:10:29 -0700392 private void retrieveRib(){
393 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
394 String response = RestClient.get(url);
395
396 if (response.equals("")){
397 return;
398 }
399
400 response = response.replaceAll("\"", "'");
401 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
402 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
403 String router_id = jsonObj.getString("router-id");
404
405 int size = rib_json_array.size();
406
407 log.info("Retrived RIB of {} entries from BGPd", size);
408
409 for (int j = 0; j < size; j++) {
410 JSONObject second_json_object = rib_json_array.getJSONObject(j);
411 String prefix = second_json_object.getString("prefix");
412 String nexthop = second_json_object.getString("nexthop");
413
414 //insert each rib entry into the local rib;
415 String[] substring = prefix.split("/");
416 String prefix1 = substring[0];
417 String mask1 = substring[1];
418
419 Prefix p;
420 try {
421 p = new Prefix(prefix1, Integer.valueOf(mask1));
422 } catch (NumberFormatException e) {
423 log.warn("Wrong mask format in RIB JSON: {}", mask1);
424 continue;
425 } catch (UnknownHostException e1) {
426 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
427 continue;
428 }
429
430 PtreeNode node = ptree.acquire(p.getAddress(), p.masklen);
431 Rib rib = new Rib(router_id, nexthop, p.masklen);
432
433 if (node.rib != null) {
434 node.rib = null;
435 ptree.delReference(node);
436 }
437
438 node.rib = rib;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700439
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200440 prefixAdded(node);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700441 }
442 }
443
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200444 public void prefixAdded(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200445 if (!topologyReady){
446 return;
447 }
448
449 String prefix = getPrefixFromPtree(node);
450
451 log.debug("New prefix {} added, next hop {}",
452 prefix, node.rib.nextHop.toString());
453
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700454 //Add a flow to rewrite mac for this prefix to all border switches
Jonathan Hartd1f23252013-06-13 15:17:05 +1200455 GatewayRouter thisRouter = gatewayRouters
456 .get(InetAddresses.toAddrString(node.rib.nextHop));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700457
458 if (thisRouter == null){
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200459 //TODO local router isn't in gateway list so this will get thrown
460 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
461 log.error("Couldn't find next hop router in router {} in config"
462 , node.rib.nextHop.toString());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700463 return; //just quit out here? This is probably a configuration error
464 }
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200465
Jonathan Hartd1f23252013-06-13 15:17:05 +1200466 for (GatewayRouter ingressRouter : gatewayRouters.values()){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700467 if (ingressRouter == thisRouter) {
468 continue;
469 }
470
471 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200472 ingressRouter.getAttachmentPoint(),
473 thisRouter.getAttachmentPoint());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700474
475 if (shortestPath == null){
476 log.debug("Shortest path between {} and {} not found",
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200477 ingressRouter.getAttachmentPoint(),
478 thisRouter.getAttachmentPoint());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700479 return; // just quit here?
480 }
481
482 //TODO check the shortest path against the cached version we
483 //calculated before. If they don't match up that's a problem
484
485 //Set up the flow mod
486 OFFlowMod fm =
487 (OFFlowMod) floodlightProvider.getOFMessageFactory()
488 .getMessage(OFType.FLOW_MOD);
489
490 fm.setIdleTimeout((short)0)
491 .setHardTimeout((short)0)
492 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
493 .setCookie(MAC_RW_COOKIE)
494 .setCommand(OFFlowMod.OFPFC_ADD)
495 //.setMatch(match)
496 //.setActions(actions)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200497 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700498 .setLengthU(OFFlowMod.MINIMUM_LENGTH
499 + OFActionDataLayerDestination.MINIMUM_LENGTH
500 + OFActionOutput.MINIMUM_LENGTH);
501
502 OFMatch match = new OFMatch();
503 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200504 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700505
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200506 match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
507 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200508
509 InetAddress address = null;
510 try {
511 address = InetAddress.getByAddress(node.key);
512 } catch (UnknownHostException e1) {
513 //Should never happen is the reverse conversion has already been done
514 log.error("Malformed IP address");
515 return;
516 }
517
518 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
519 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700520
521 //Set up MAC rewrite action
522 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
523 macRewriteAction.setDataLayerAddress(thisRouter.getRouterMac().toBytes());
524
525 //Set up output action
526 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200527 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700528
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200529 Port outputPort = shortestPath.flowEntries().get(0).outPort();
530 outputAction.setPort(outputPort.value());
531
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700532 List<OFAction> actions = new ArrayList<OFAction>();
533 actions.add(macRewriteAction);
534 actions.add(outputAction);
535 fm.setActions(actions);
536
537 //Write to switch
538 IOFSwitch sw = floodlightProvider.getSwitches()
539 .get(ingressRouter.getAttachmentPoint().dpid().value());
540
541 if (sw == null){
542 log.warn("Switch not found when pushing flow mod");
543 continue;
544 }
545
546 List<OFMessage> msglist = new ArrayList<OFMessage>();
547 msglist.add(fm);
548 try {
549 sw.write(msglist, null);
550 sw.flush();
551 } catch (IOException e) {
552 log.error("Failure writing flow mod", e);
553 }
554 }
555 }
556
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200557 public void prefixDeleted(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200558 if (!topologyReady) {
559 return;
560 }
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200561
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200562 String prefix = getPrefixFromPtree(node);
563
564 log.debug("Prefix {} deleted, next hop {}",
565 prefix, node.rib.nextHop.toString());
566
567 //Remove MAC rewriting flows from other border switches
568 GatewayRouter thisRouter = gatewayRouters
569 .get(InetAddresses.toAddrString(node.rib.nextHop));
570
571 for (GatewayRouter ingressRouter : gatewayRouters.values()){
572 if (ingressRouter == thisRouter) {
573 continue;
574 }
575
576 //Set up the flow mod
577 OFFlowMod fm =
578 (OFFlowMod) floodlightProvider.getOFMessageFactory()
579 .getMessage(OFType.FLOW_MOD);
580
581 fm.setIdleTimeout((short)0)
582 .setHardTimeout((short)0)
583 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
584 .setCookie(MAC_RW_COOKIE)
585 .setCommand(OFFlowMod.OFPFC_DELETE)
586 //.setMatch(match)
587 //.setActions(actions)
588 .setPriority(SDNIP_PRIORITY)
589 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
590 //+ OFActionDataLayerDestination.MINIMUM_LENGTH
591 //+ OFActionOutput.MINIMUM_LENGTH);
592
593 OFMatch match = new OFMatch();
594 match.setDataLayerType(Ethernet.TYPE_IPv4);
595 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
596
597 match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
598 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
599
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200600 InetAddress address = null;
601 try {
602 address = InetAddress.getByAddress(node.key);
603 } catch (UnknownHostException e1) {
604 //Should never happen is the reverse conversion has already been done
605 log.error("Malformed IP address");
606 return;
607 }
608
609 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
610 fm.setMatch(match);
611
612 //Write to switch
613 IOFSwitch sw = floodlightProvider.getSwitches()
614 .get(ingressRouter.getAttachmentPoint().dpid().value());
615
616 if (sw == null){
617 log.warn("Switch not found when pushing flow mod");
618 continue;
619 }
620
621 List<OFMessage> msglist = new ArrayList<OFMessage>();
622 msglist.add(fm);
623 try {
624 sw.write(msglist, null);
625 sw.flush();
626 } catch (IOException e) {
627 log.error("Failure writing flow mod", e);
628 }
629 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700630 }
631
632 /*
633 * On startup we need to calculate a full mesh of paths between all gateway
634 * switches
635 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200636 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700637 Map<IOFSwitch, SwitchPort> gatewaySwitches = new HashMap<IOFSwitch, SwitchPort>();
638
639 //have to account for switches not being there, paths not being found.
640
Jonathan Hartd1f23252013-06-13 15:17:05 +1200641 for (GatewayRouter router : gatewayRouters.values()){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700642 SwitchPort switchPort = router.getAttachmentPoint();
643
644 IOFSwitch sw = floodlightProvider.getSwitches().get(switchPort.dpid().value());
645
646 if (sw == null){
647 log.debug("Gateway switch {} not here yet", switchPort.dpid().value());
648 return; // just quit here?
649 }
650
651 //Only need to know 1 external-facing port from each gateway switch
652 //which we can feed into shortest path calculation
653 if (!gatewaySwitches.containsKey(sw)){
654 gatewaySwitches.put(sw, switchPort);
655 }
656
657 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700658
659 //For each border router, calculate and install a path from every other
660 //border switch to said border router. However, don't install the entry
661 //in to the first hop switch, as we need to install an entry to rewrite
662 //for each prefix received. This will be done later when prefixes have
663 //actually been received.
664
Jonathan Hartd1f23252013-06-13 15:17:05 +1200665 for (GatewayRouter dstRouter : gatewayRouters.values()){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700666 SwitchPort routerAttachmentPoint = dstRouter.getAttachmentPoint();
667 for (Map.Entry<IOFSwitch, SwitchPort> src : gatewaySwitches.entrySet()) {
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700668
669 if (routerAttachmentPoint.dpid().value() ==
670 src.getKey().getId()){
671 continue;
672 }
673
674 DataPath shortestPath = topoRouteService.getShortestPath(
675 src.getValue(), routerAttachmentPoint);
676
677 if (shortestPath == null){
678 log.debug("Shortest path between {} and {} not found",
679 src.getValue(), routerAttachmentPoint);
680 return; // just quit here?
681 }
682
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700683 //install flows
684 installPath(shortestPath.flowEntries(), dstRouter);
685 }
686 }
687 }
688
689 private void installPath(List<FlowEntry> flowEntries, GatewayRouter router){
690
691 //Set up the flow mod
692 OFFlowMod fm =
693 (OFFlowMod) floodlightProvider.getOFMessageFactory()
694 .getMessage(OFType.FLOW_MOD);
695
696 OFActionOutput action = new OFActionOutput();
697 action.setMaxLength((short)0xffff);
698 List<OFAction> actions = new ArrayList<OFAction>();
699 actions.add(action);
700
701 fm.setIdleTimeout((short)0)
702 .setHardTimeout((short)0)
703 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
704 .setCookie(L2_FWD_COOKIE)
705 .setCommand(OFFlowMod.OFPFC_ADD)
706 //.setMatch(match)
707 .setActions(actions)
708 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
709
710 //Don't push the first flow entry. We need to push entries in the
711 //first switch based on IP prefix which we don't know yet.
712 for (int i = 1; i < flowEntries.size(); i++){
713 FlowEntry flowEntry = flowEntries.get(i);
714
715 OFMatch match = new OFMatch();
716 match.setDataLayerDestination(router.getRouterMac().toBytes());
717 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
718 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
719
720 fm.setMatch(match);
721
722 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
723
724 if (sw == null){
725 log.warn("Switch not found when pushing flow mod");
726 continue;
727 }
728
729 List<OFMessage> msglist = new ArrayList<OFMessage>();
730 msglist.add(fm);
731 try {
732 sw.write(msglist, null);
733 sw.flush();
734 } catch (IOException e) {
735 log.error("Failure writing flow mod", e);
736 }
737
738 try {
739 fm = fm.clone();
740 } catch (CloneNotSupportedException e1) {
741 log.error("Failure cloning flow mod", e1);
742 }
743 }
744 }
745
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200746 private void setupBgpPaths(){
747 for (BgpPeer bgpPeer : bgpPeers){
748 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
749
750 DataPath path = topoRouteService.getShortestPath(
751 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
752
753 if (path == null){
754 log.debug("Unable to compute path for BGP traffic for {}",
755 bgpPeer.getIpAddress());
756 continue;
757 }
758
759 //Set up the flow mod
760 OFFlowMod fm =
761 (OFFlowMod) floodlightProvider.getOFMessageFactory()
762 .getMessage(OFType.FLOW_MOD);
763
764 OFActionOutput action = new OFActionOutput();
765 action.setMaxLength((short)0xffff);
766 List<OFAction> actions = new ArrayList<OFAction>();
767 actions.add(action);
768
769 fm.setIdleTimeout((short)0)
770 .setHardTimeout((short)0)
771 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
772 .setCookie(BGP_COOKIE)
773 .setCommand(OFFlowMod.OFPFC_ADD)
774 .setPriority(SDNIP_PRIORITY)
775 .setActions(actions)
776 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
777
778 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
779 OFMatch forwardMatchSrc = new OFMatch();
780
781
782 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
783 + "/32";
784 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
785 + "/32";
786
787 //Common match fields
788 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
789 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
790 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
791 forwardMatchSrc.setTransportDestination(BGP_PORT);
792 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
793 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
794
795
796 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
797
798 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
799 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
800
801 OFMatch forwardMatchDst = forwardMatchSrc.clone();
802
803 forwardMatchSrc.setTransportSource(BGP_PORT);
804 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
805 forwardMatchDst.setTransportDestination(BGP_PORT);
806 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
807
808 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
809 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
810
811 OFMatch reverseMatchDst = reverseMatchSrc.clone();
812
813 reverseMatchSrc.setTransportSource(BGP_PORT);
814 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
815 reverseMatchDst.setTransportDestination(BGP_PORT);
816 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
817
818 fm.setMatch(forwardMatchSrc);
819
820 for (FlowEntry flowEntry : path.flowEntries()){
821 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
822 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
823 try {
824 forwardFlowModSrc = fm.clone();
825 forwardFlowModDst = fm.clone();
826 reverseFlowModSrc = fm.clone();
827 reverseFlowModDst = fm.clone();
828 } catch (CloneNotSupportedException e) {
829 log.warn("Clone failed", e);
830 continue;
831 }
832
833 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
834 forwardFlowModSrc.setMatch(forwardMatchSrc);
835 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
836 .setPort(flowEntry.outPort().value());
837
838 forwardMatchDst.setInputPort(flowEntry.inPort().value());
839 forwardFlowModDst.setMatch(forwardMatchDst);
840 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
841 .setPort(flowEntry.outPort().value());
842
843 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
844 reverseFlowModSrc.setMatch(reverseMatchSrc);
845 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
846 .setPort(flowEntry.inPort().value());
847
848 reverseMatchDst.setInputPort(flowEntry.outPort().value());
849 reverseFlowModDst.setMatch(reverseMatchDst);
850 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
851 .setPort(flowEntry.inPort().value());
852
853 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
854
855 //Hopefully the switch is there
856 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
857 msgList.add(forwardFlowModSrc);
858 msgList.add(forwardFlowModDst);
859 msgList.add(reverseFlowModSrc);
860 msgList.add(reverseFlowModDst);
861
862 try {
863 sw.write(msgList, null);
864 sw.flush();
865 } catch (IOException e) {
866 log.error("Failure writing flow mod", e);
867 }
868 }
869 }
870 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200871
872 private void beginRouting(){
873 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200874 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200875 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200876
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200877 //Traverse ptree and create flows for all routes
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200878 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
879 if (node.rib != null){
880 prefixAdded(node);
881 }
882 }
883 }
884
885 private void checkSwitchesConnected(){
886 for (String dpid : switches){
887 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
888 log.debug("Not all switches are here yet");
889 return;
890 }
891 }
892 switchesConnected = true;
893 }
894
895 private void checkTopologyReady(){
896 for (GatewayRouter dstRouter : gatewayRouters.values()){
897 SwitchPort dstAttachmentPoint = dstRouter.getAttachmentPoint();
898 for (GatewayRouter srcRouter : gatewayRouters.values()) {
899
900 if (dstRouter == srcRouter){
901 continue;
902 }
903
904 SwitchPort srcAttachmentPoint = srcRouter.getAttachmentPoint();
905
906 DataPath shortestPath = topoRouteService.getShortestPath(
907 srcAttachmentPoint, dstAttachmentPoint);
908
909 if (shortestPath == null){
910 log.debug("Shortest path between {} and {} not found",
911 srcAttachmentPoint, dstAttachmentPoint);
912 return;
913 }
914 }
915 }
916 topologyReady = true;
917 }
918
919 private void checkStatus(){
920 log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
921
922 if (!switchesConnected){
923 checkSwitchesConnected();
924 }
925 boolean oldTopologyReadyStatus = topologyReady;
926 if (switchesConnected && !topologyReady){
927 checkTopologyReady();
928 }
929 if (!oldTopologyReadyStatus && topologyReady){
930 beginRouting();
931 }
932 }
933
pingping-lina2cbfad2013-03-07 08:39:21 +0800934 @Override
935 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +0800936 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200937 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700938 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +0800939
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200940 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
941
Jonathan Hart61ba9372013-05-19 20:10:29 -0700942 //Retrieve the RIB from BGPd during startup
943 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800944 }
945
946 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200947 public void topologyChanged() {
948 //There seems to be more topology events than there should be. Lots of link
949 //updated, port up and switch updated on what should be a fairly static topology
pingping-lina2cbfad2013-03-07 08:39:21 +0800950
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200951 boolean refreshNeeded = false;
952 for (LDUpdate ldu : topology.getLastLinkUpdates()){
953 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
954 //We don't need to recalculate anything for just link updates
955 //They happen way too frequently (may be a bug in our link discovery)
956 refreshNeeded = true;
957 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200958
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200959 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200960 /*
961 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
962 log.debug("Link Added: src={} outPort={} dst={} inPort={}",
963 new Object[] {
964 HexString.toHexString(ldu.getSrc()), ldu.getSrcPort(),
965 HexString.toHexString(ldu.getDst()), ldu.getDstPort()});
966 TopoLinkServiceImpl impl = new TopoLinkServiceImpl();
967
968 List<Link> retval = impl.getActiveLinks();
969
970 log.debug("retval size {}", retval.size());
971
972 for (Link l : retval){
973 log.debug("link {}", l);
974 }
975 }
976 */
977 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
978 synchronized (linkUpdates) {
979 linkUpdates.add(ldu);
980 }
981 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200982 }
983
984 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200985 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
986 /*if (topologyReady){
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200987 setupFullMesh();
988 }
989 else{
990 checkStatus();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200991 }*/
992
pingping-lina2cbfad2013-03-07 08:39:21 +0800993 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200994 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800995
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200996 //TODO determine whether we need to listen for switch joins
997 @Override
998 public void addedSwitch(IOFSwitch sw) {
999 //checkStatus();
1000 }
1001
1002 @Override
1003 public void removedSwitch(IOFSwitch sw) {
1004 // TODO Auto-generated method stub
1005 }
1006
1007 @Override
1008 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001009
1010 @Override
1011 public String getName() {
1012 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +08001013 }
1014}