blob: baa825bcf444afc7e7a0cc665b5d4de2bfce5519 [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;
pingping-lina2cbfad2013-03-07 08:39:21 +08009import java.util.HashMap;
Jonathan Hart98957bf2013-07-01 14:49:24 +120010import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070011import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070012import java.util.Map;
Jonathan Hart98957bf2013-07-01 14:49:24 +120013import java.util.concurrent.Executors;
14import java.util.concurrent.ScheduledExecutorService;
15import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080016
Jonathan Hart61ba9372013-05-19 20:10:29 -070017import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070018import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120019import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080020import net.floodlightcontroller.core.module.FloodlightModuleContext;
21import net.floodlightcontroller.core.module.FloodlightModuleException;
22import net.floodlightcontroller.core.module.IFloodlightModule;
23import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120024import net.floodlightcontroller.core.util.SingletonTask;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070025import net.floodlightcontroller.devicemanager.IDeviceService;
26import net.floodlightcontroller.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120027import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080028import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120029import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080030import net.floodlightcontroller.topology.ITopologyListener;
31import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120032import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070033import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120034import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070035import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
36import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120037import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070038import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120039import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070040import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070041import net.onrc.onos.ofcontroller.util.Port;
42import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080043import net.sf.json.JSONArray;
44import net.sf.json.JSONObject;
45import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080046
Jonathan Hartd1f23252013-06-13 15:17:05 +120047import org.codehaus.jackson.JsonParseException;
48import org.codehaus.jackson.map.JsonMappingException;
49import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070050import org.openflow.protocol.OFFlowMod;
51import org.openflow.protocol.OFMatch;
52import org.openflow.protocol.OFMessage;
53import org.openflow.protocol.OFPacketOut;
54import org.openflow.protocol.OFType;
55import org.openflow.protocol.action.OFAction;
56import org.openflow.protocol.action.OFActionDataLayerDestination;
57import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120058import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080059import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
Jonathan Hart1236a9b2013-06-18 22:10:05 +120062public class BgpRoute implements IFloodlightModule, IBgpRouteService,
63 ITopologyListener, IOFSwitchListener {
pingping-lina2cbfad2013-03-07 08:39:21 +080064
65 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
66
67 protected IFloodlightProviderService floodlightProvider;
68 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070069 protected ITopoRouteService topoRouteService;
70 protected IDeviceService devices;
71 protected IRestApiService restApi;
72
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120073 protected ProxyArpManager proxyArp;
74
pingping-lina2cbfad2013-03-07 08:39:21 +080075 protected static Ptree ptree;
Jonathan Hart61ba9372013-05-19 20:10:29 -070076 protected String bgpdRestIp;
77 protected String routerId;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120078 protected String gatewaysFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070079
80 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
81 //the controller/OS should hand out cookie IDs to prevent conflicts.
82 protected final long APP_COOKIE = 0xa0000000000000L;
83 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
84 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
85 //Cookie for flows in ingress switches that rewrite the MAC address
86 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120087 //Cookie for flows that setup BGP paths
88 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +120089 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
90 //need to be higher priority than this otherwise the rewrite may not get done
91 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070092
Jonathan Hart832a7cb2013-06-24 11:25:35 +120093 protected final short BGP_PORT = 179;
94
Jonathan Hart98957bf2013-07-01 14:49:24 +120095 protected final int TOPO_DETECTION_WAIT = 2; //seconds
96
Jonathan Hart832a7cb2013-06-24 11:25:35 +120097 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +120098 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120099 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200100 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200101 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200102
103 //True when all switches have connected
104 protected volatile boolean switchesConnected = false;
105 //True when we have a full mesh of shortest paths between gateways
106 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200107
Jonathan Hart98957bf2013-07-01 14:49:24 +1200108 protected ArrayList<LDUpdate> linkUpdates;
109 protected SingletonTask topologyChangeDetectorTask;
110
Jonathan Hart98957bf2013-07-01 14:49:24 +1200111 protected class TopologyChangeDetector implements Runnable {
112 @Override
113 public void run() {
114 log.debug("Running topology change detection task");
115 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200116 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200117 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
118
119 List<Link> activeLinks = topoLinkService.getActiveLinks();
120 for (Link l : activeLinks){
121 log.debug("active link: {}", l);
122 }
123
124 Iterator<LDUpdate> it = linkUpdates.iterator();
125 while (it.hasNext()){
126 LDUpdate ldu = it.next();
127 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
128 ldu.getDst(), ldu.getDstPort());
129
130 if (activeLinks.contains(l)){
131 log.debug("Not found: {}", l);
132 it.remove();
133 }
134 }
135 }
136
137 if (linkUpdates.isEmpty()){
138 //All updates have been seen in network map.
139 //We can check if topology is ready
140 log.debug("No know changes outstanding. Checking topology now");
141 checkStatus();
142 }
143 else {
144 //We know of some link updates that haven't propagated to the database yet
145 log.debug("Some changes not found in network map- size {}", linkUpdates.size());
146 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
147 }
148 }
149 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700150
Jonathan Hartd1f23252013-06-13 15:17:05 +1200151 private void readGatewaysConfiguration(String gatewaysFilename){
152 File gatewaysFile = new File(gatewaysFilename);
153 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700154
Jonathan Hartd1f23252013-06-13 15:17:05 +1200155 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200156 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
157
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200158 switches = config.getSwitches();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200159 interfaces = config.getInterfaces();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200160 bgpPeers = new HashMap<InetAddress, BgpPeer>();
161 for (BgpPeer peer : config.getPeers()){
162 bgpPeers.put(peer.getIpAddress(), peer);
163 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200164
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200165 bgpdAttachmentPoint = new SwitchPort(
166 new Dpid(config.getBgpdAttachmentDpid()),
167 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200168
Jonathan Hartd1f23252013-06-13 15:17:05 +1200169 } catch (JsonParseException e) {
170 log.error("Error in JSON file", e);
171 System.exit(1);
172 } catch (JsonMappingException e) {
173 log.error("Error in JSON file", e);
174 System.exit(1);
175 } catch (IOException e) {
176 log.error("Error reading JSON file", e);
177 System.exit(1);
178 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700179 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800180
181 @Override
182 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700183 Collection<Class<? extends IFloodlightService>> l
184 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800185 l.add(IBgpRouteService.class);
186 return l;
187 }
188
189 @Override
190 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700191 Map<Class<? extends IFloodlightService>, IFloodlightService> m
192 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800193 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800194 return m;
195 }
196
pingping-lina2cbfad2013-03-07 08:39:21 +0800197 @Override
198 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700199 Collection<Class<? extends IFloodlightService>> l
200 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800201 l.add(IFloodlightProviderService.class);
202 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700203 l.add(ITopoRouteService.class);
204 l.add(IDeviceService.class);
205 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800206 return l;
207 }
208
209 @Override
210 public void init(FloodlightModuleContext context)
211 throws FloodlightModuleException {
212
213 ptree = new Ptree(32);
Jonathan Hartc824ad02013-07-03 15:58:45 +1200214
pingping-lina2cbfad2013-03-07 08:39:21 +0800215 // Register floodlight provider and REST handler.
216 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800217 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700218 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
219 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200220 restApi = context.getServiceImpl(IRestApiService.class);
221
222 //TODO We'll initialise this here for now, but it should really be done as
223 //part of the controller core
224 proxyArp = new ProxyArpManager(floodlightProvider, topology);
pingping-lina2cbfad2013-03-07 08:39:21 +0800225
Jonathan Hart98957bf2013-07-01 14:49:24 +1200226 linkUpdates = new ArrayList<LDUpdate>();
227 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
228 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
229
Jonathan Hart61ba9372013-05-19 20:10:29 -0700230 //Read in config values
231 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
232 if (bgpdRestIp == null){
233 log.error("BgpdRestIp property not found in config file");
234 System.exit(1);
235 }
236 else {
237 log.info("BgpdRestIp set to {}", bgpdRestIp);
238 }
239
240 routerId = context.getConfigParams(this).get("RouterId");
241 if (routerId == null){
242 log.error("RouterId property not found in config file");
243 System.exit(1);
244 }
245 else {
246 log.info("RouterId set to {}", routerId);
247 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200248
249 readGatewaysConfiguration(gatewaysFilename);
pingping-lina2cbfad2013-03-07 08:39:21 +0800250 // Test.
251 //test();
252 }
253
254 public Ptree getPtree() {
255 return ptree;
256 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700257
258 public void clearPtree() {
259 //ptree = null;
260 ptree = new Ptree(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800261 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700262
pingping-line2a09ca2013-03-23 09:33:58 +0800263 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700264 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800265 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700266
pingping-line2a09ca2013-03-23 09:33:58 +0800267 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700268 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800269 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800270
271 // Return nexthop address as byte array.
272 public Rib lookupRib(byte[] dest) {
273 if (ptree == null) {
274 log.debug("lookupRib: ptree null");
275 return null;
276 }
277
278 PtreeNode node = ptree.match(dest, 32);
279 if (node == null) {
280 log.debug("lookupRib: ptree node null");
281 return null;
282 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700283
pingping-lina2cbfad2013-03-07 08:39:21 +0800284 if (node.rib == null) {
285 log.debug("lookupRib: ptree rib null");
286 return null;
287 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700288
pingping-lina2cbfad2013-03-07 08:39:21 +0800289 ptree.delReference(node);
290
291 return node.rib;
292 }
293
Jonathan Hart61ba9372013-05-19 20:10:29 -0700294 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800295 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700296 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800297 System.out.println("Here it is");
298 Prefix p = new Prefix("128.0.0.0", 8);
299 Prefix q = new Prefix("8.0.0.0", 8);
300 Prefix r = new Prefix("10.0.0.0", 24);
301 Prefix a = new Prefix("10.0.0.1", 32);
302
303 ptree.acquire(p.getAddress(), p.masklen);
304 ptree.acquire(q.getAddress(), q.masklen);
305 ptree.acquire(r.getAddress(), r.masklen);
306
307 System.out.println("Traverse start");
308 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
309 Prefix p_result = new Prefix(node.key, node.keyBits);
310 }
311
312 PtreeNode n = ptree.match(a.getAddress(), a.masklen);
313 if (n != null) {
314 System.out.println("Matched prefix for 10.0.0.1:");
315 Prefix x = new Prefix(n.key, n.keyBits);
316 ptree.delReference(n);
317 }
318
319 n = ptree.lookup(p.getAddress(), p.masklen);
320 if (n != null) {
321 ptree.delReference(n);
322 ptree.delReference(n);
323 }
324 System.out.println("Traverse start");
325 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
326 Prefix p_result = new Prefix(node.key, node.keyBits);
327 }
328
329 n = ptree.lookup(q.getAddress(), q.masklen);
330 if (n != null) {
331 ptree.delReference(n);
332 ptree.delReference(n);
333 }
334 System.out.println("Traverse start");
335 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
336 Prefix p_result = new Prefix(node.key, node.keyBits);
337 }
338
339 n = ptree.lookup(r.getAddress(), r.masklen);
340 if (n != null) {
341 ptree.delReference(n);
342 ptree.delReference(n);
343 }
344 System.out.println("Traverse start");
345 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
346 Prefix p_result = new Prefix(node.key, node.keyBits);
347 }
348
349 }
350
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200351 private String getPrefixFromPtree(PtreeNode node){
352 InetAddress address = null;
353 try {
354 address = InetAddress.getByAddress(node.key);
355 } catch (UnknownHostException e1) {
356 //Should never happen is the reverse conversion has already been done
357 log.error("Malformed IP address");
358 return "";
359 }
360 return address.toString() + "/" + node.rib.masklen;
361 }
362
Jonathan Hart61ba9372013-05-19 20:10:29 -0700363 private void retrieveRib(){
364 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
365 String response = RestClient.get(url);
366
367 if (response.equals("")){
368 return;
369 }
370
371 response = response.replaceAll("\"", "'");
372 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
373 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
374 String router_id = jsonObj.getString("router-id");
375
376 int size = rib_json_array.size();
377
378 log.info("Retrived RIB of {} entries from BGPd", size);
379
380 for (int j = 0; j < size; j++) {
381 JSONObject second_json_object = rib_json_array.getJSONObject(j);
382 String prefix = second_json_object.getString("prefix");
383 String nexthop = second_json_object.getString("nexthop");
384
385 //insert each rib entry into the local rib;
386 String[] substring = prefix.split("/");
387 String prefix1 = substring[0];
388 String mask1 = substring[1];
389
390 Prefix p;
391 try {
392 p = new Prefix(prefix1, Integer.valueOf(mask1));
393 } catch (NumberFormatException e) {
394 log.warn("Wrong mask format in RIB JSON: {}", mask1);
395 continue;
396 } catch (UnknownHostException e1) {
397 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
398 continue;
399 }
400
401 PtreeNode node = ptree.acquire(p.getAddress(), p.masklen);
402 Rib rib = new Rib(router_id, nexthop, p.masklen);
403
404 if (node.rib != null) {
405 node.rib = null;
406 ptree.delReference(node);
407 }
408
409 node.rib = rib;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700410
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200411 prefixAdded(node);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700412 }
413 }
414
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200415 public void prefixAdded(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200416 if (!topologyReady){
417 return;
418 }
419
420 String prefix = getPrefixFromPtree(node);
421
Jonathan Hartc824ad02013-07-03 15:58:45 +1200422 log.debug("New prefix {} added, next hop {}, routerId {}",
423 new Object[] {prefix, node.rib.nextHop.toString(),
424 node.rib.routerId.getHostAddress()});
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200425
Jonathan Hartc824ad02013-07-03 15:58:45 +1200426 //TODO this is wrong, we shouldn't be dealing with BGP peers here.
427 //We need to figure out where the device is attached and what it's
428 //mac address is by learning.
429 //The next hop is not necessarily the peer, and the peer's attachment
430 //point is not necessarily the next hop's attachment point.
431 BgpPeer peer = bgpPeers.get(node.rib.nextHop);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700432
Jonathan Hartc824ad02013-07-03 15:58:45 +1200433 if (peer == null){
434 //TODO local router isn't in peers list so this will get thrown
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200435 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
Jonathan Hartc824ad02013-07-03 15:58:45 +1200436
437 //The other scenario is this is a route server route. In that
438 //case the next hop is not in our configuration
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200439 log.error("Couldn't find next hop router in router {} in config"
440 , node.rib.nextHop.toString());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700441 return; //just quit out here? This is probably a configuration error
442 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200443
444 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200445
Jonathan Hartc824ad02013-07-03 15:58:45 +1200446 //Add a flow to rewrite mac for this prefix to all border switches
447 for (Interface srcInterface : interfaces.values()) {
448 if (srcInterface == peerInterface) {
449 //Don't push a flow for the switch where this peer is attached
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700450 continue;
451 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200452
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700453 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200454 srcInterface.getSwitchPort(),
455 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700456
457 if (shortestPath == null){
458 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200459 srcInterface.getSwitchPort(),
460 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700461 return; // just quit here?
462 }
463
464 //TODO check the shortest path against the cached version we
465 //calculated before. If they don't match up that's a problem
466
467 //Set up the flow mod
468 OFFlowMod fm =
469 (OFFlowMod) floodlightProvider.getOFMessageFactory()
470 .getMessage(OFType.FLOW_MOD);
471
472 fm.setIdleTimeout((short)0)
473 .setHardTimeout((short)0)
474 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
475 .setCookie(MAC_RW_COOKIE)
476 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200477 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700478 .setLengthU(OFFlowMod.MINIMUM_LENGTH
479 + OFActionDataLayerDestination.MINIMUM_LENGTH
480 + OFActionOutput.MINIMUM_LENGTH);
481
482 OFMatch match = new OFMatch();
483 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200484 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700485
Jonathan Hartc824ad02013-07-03 15:58:45 +1200486 //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
487 //match.setDataLayerSource(peer.getMacAddress().toBytes());
488 //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200489
490 InetAddress address = null;
491 try {
492 address = InetAddress.getByAddress(node.key);
493 } catch (UnknownHostException e1) {
494 //Should never happen is the reverse conversion has already been done
495 log.error("Malformed IP address");
496 return;
497 }
498
499 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
500 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700501
502 //Set up MAC rewrite action
503 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200504 //TODO use ARP module rather than configured mac addresses
505 //TODO the peer's mac address is not necessarily the next hop's...
506 macRewriteAction.setDataLayerAddress(peer.getMacAddress().toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700507
508 //Set up output action
509 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200510 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700511
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200512 Port outputPort = shortestPath.flowEntries().get(0).outPort();
513 outputAction.setPort(outputPort.value());
514
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700515 List<OFAction> actions = new ArrayList<OFAction>();
516 actions.add(macRewriteAction);
517 actions.add(outputAction);
518 fm.setActions(actions);
519
520 //Write to switch
521 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200522 .get(srcInterface.getDpid());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700523
524 if (sw == null){
525 log.warn("Switch not found when pushing flow mod");
526 continue;
527 }
528
529 List<OFMessage> msglist = new ArrayList<OFMessage>();
530 msglist.add(fm);
531 try {
532 sw.write(msglist, null);
533 sw.flush();
534 } catch (IOException e) {
535 log.error("Failure writing flow mod", e);
536 }
537 }
538 }
539
Jonathan Hartc824ad02013-07-03 15:58:45 +1200540 //TODO this is largely untested
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200541 public void prefixDeleted(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200542 if (!topologyReady) {
543 return;
544 }
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200545
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200546 String prefix = getPrefixFromPtree(node);
547
548 log.debug("Prefix {} deleted, next hop {}",
549 prefix, node.rib.nextHop.toString());
550
551 //Remove MAC rewriting flows from other border switches
Jonathan Hartc824ad02013-07-03 15:58:45 +1200552 BgpPeer peer = bgpPeers.get(node.rib.nextHop);
553 if (peer == null){
554 //either a router server route or local route. Can't handle right now
555 return;
556 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200557
Jonathan Hartc824ad02013-07-03 15:58:45 +1200558 Interface peerInterface = interfaces.get(peer.getInterfaceName());
559
560 for (Interface srcInterface : interfaces.values()) {
561 if (srcInterface == peerInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200562 continue;
563 }
564
565 //Set up the flow mod
566 OFFlowMod fm =
567 (OFFlowMod) floodlightProvider.getOFMessageFactory()
568 .getMessage(OFType.FLOW_MOD);
569
570 fm.setIdleTimeout((short)0)
571 .setHardTimeout((short)0)
572 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
573 .setCookie(MAC_RW_COOKIE)
574 .setCommand(OFFlowMod.OFPFC_DELETE)
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200575 .setPriority(SDNIP_PRIORITY)
576 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
577 //+ OFActionDataLayerDestination.MINIMUM_LENGTH
578 //+ OFActionOutput.MINIMUM_LENGTH);
579
580 OFMatch match = new OFMatch();
581 match.setDataLayerType(Ethernet.TYPE_IPv4);
582 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
583
Jonathan Hartc824ad02013-07-03 15:58:45 +1200584 //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
585 //match.setDataLayerSource(peer.getMacAddress().toBytes());
586 //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200587
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200588 InetAddress address = null;
589 try {
590 address = InetAddress.getByAddress(node.key);
591 } catch (UnknownHostException e1) {
592 //Should never happen is the reverse conversion has already been done
593 log.error("Malformed IP address");
594 return;
595 }
596
597 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
598 fm.setMatch(match);
599
600 //Write to switch
601 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200602 .get(srcInterface.getDpid());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200603
604 if (sw == null){
605 log.warn("Switch not found when pushing flow mod");
606 continue;
607 }
608
609 List<OFMessage> msglist = new ArrayList<OFMessage>();
610 msglist.add(fm);
611 try {
612 sw.write(msglist, null);
613 sw.flush();
614 } catch (IOException e) {
615 log.error("Failure writing flow mod", e);
616 }
617 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700618 }
619
620 /*
621 * On startup we need to calculate a full mesh of paths between all gateway
622 * switches
623 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200624 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700625 //For each border router, calculate and install a path from every other
626 //border switch to said border router. However, don't install the entry
627 //in to the first hop switch, as we need to install an entry to rewrite
628 //for each prefix received. This will be done later when prefixes have
629 //actually been received.
630
Jonathan Hartc824ad02013-07-03 15:58:45 +1200631 for (BgpPeer peer : bgpPeers.values()) {
632 Interface peerInterface = interfaces.get(peer.getInterfaceName());
633 for (Map.Entry<String, Interface> intfEntry : interfaces.entrySet()) {
634 Interface srcInterface = intfEntry.getValue();
635 if (peer.getInterfaceName().equals(intfEntry.getKey())){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700636 continue;
637 }
638
639 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200640 srcInterface.getSwitchPort(), peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700641
642 if (shortestPath == null){
643 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200644 srcInterface.getSwitchPort(), peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700645 return; // just quit here?
646 }
647
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700648 //install flows
Jonathan Hartc824ad02013-07-03 15:58:45 +1200649 installPath(shortestPath.flowEntries(), peer);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700650 }
651 }
652 }
653
Jonathan Hartc824ad02013-07-03 15:58:45 +1200654 private void installPath(List<FlowEntry> flowEntries, BgpPeer peer){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700655 //Set up the flow mod
656 OFFlowMod fm =
657 (OFFlowMod) floodlightProvider.getOFMessageFactory()
658 .getMessage(OFType.FLOW_MOD);
659
660 OFActionOutput action = new OFActionOutput();
661 action.setMaxLength((short)0xffff);
662 List<OFAction> actions = new ArrayList<OFAction>();
663 actions.add(action);
664
665 fm.setIdleTimeout((short)0)
666 .setHardTimeout((short)0)
667 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
668 .setCookie(L2_FWD_COOKIE)
669 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700670 .setActions(actions)
671 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
672
673 //Don't push the first flow entry. We need to push entries in the
674 //first switch based on IP prefix which we don't know yet.
675 for (int i = 1; i < flowEntries.size(); i++){
676 FlowEntry flowEntry = flowEntries.get(i);
677
678 OFMatch match = new OFMatch();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200679 //TODO Again using MAC address from configuration
680 match.setDataLayerDestination(peer.getMacAddress().toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700681 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
682 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
683
684 fm.setMatch(match);
685
686 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
687
688 if (sw == null){
689 log.warn("Switch not found when pushing flow mod");
690 continue;
691 }
692
693 List<OFMessage> msglist = new ArrayList<OFMessage>();
694 msglist.add(fm);
695 try {
696 sw.write(msglist, null);
697 sw.flush();
698 } catch (IOException e) {
699 log.error("Failure writing flow mod", e);
700 }
701
702 try {
703 fm = fm.clone();
704 } catch (CloneNotSupportedException e1) {
705 log.error("Failure cloning flow mod", e1);
706 }
707 }
708 }
709
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200710 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200711 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200712 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
713
714 DataPath path = topoRouteService.getShortestPath(
715 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
716
717 if (path == null){
718 log.debug("Unable to compute path for BGP traffic for {}",
719 bgpPeer.getIpAddress());
720 continue;
721 }
722
723 //Set up the flow mod
724 OFFlowMod fm =
725 (OFFlowMod) floodlightProvider.getOFMessageFactory()
726 .getMessage(OFType.FLOW_MOD);
727
728 OFActionOutput action = new OFActionOutput();
729 action.setMaxLength((short)0xffff);
730 List<OFAction> actions = new ArrayList<OFAction>();
731 actions.add(action);
732
733 fm.setIdleTimeout((short)0)
734 .setHardTimeout((short)0)
735 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
736 .setCookie(BGP_COOKIE)
737 .setCommand(OFFlowMod.OFPFC_ADD)
738 .setPriority(SDNIP_PRIORITY)
739 .setActions(actions)
740 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
741
742 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
743 OFMatch forwardMatchSrc = new OFMatch();
744
745
746 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
747 + "/32";
748 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
749 + "/32";
750
751 //Common match fields
752 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
753 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
754 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
755 forwardMatchSrc.setTransportDestination(BGP_PORT);
756 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
757 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
758
759
760 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
761
762 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
763 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
764
765 OFMatch forwardMatchDst = forwardMatchSrc.clone();
766
767 forwardMatchSrc.setTransportSource(BGP_PORT);
768 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
769 forwardMatchDst.setTransportDestination(BGP_PORT);
770 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
771
772 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
773 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
774
775 OFMatch reverseMatchDst = reverseMatchSrc.clone();
776
777 reverseMatchSrc.setTransportSource(BGP_PORT);
778 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
779 reverseMatchDst.setTransportDestination(BGP_PORT);
780 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
781
782 fm.setMatch(forwardMatchSrc);
783
784 for (FlowEntry flowEntry : path.flowEntries()){
785 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
786 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
787 try {
788 forwardFlowModSrc = fm.clone();
789 forwardFlowModDst = fm.clone();
790 reverseFlowModSrc = fm.clone();
791 reverseFlowModDst = fm.clone();
792 } catch (CloneNotSupportedException e) {
793 log.warn("Clone failed", e);
794 continue;
795 }
796
797 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
798 forwardFlowModSrc.setMatch(forwardMatchSrc);
799 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
800 .setPort(flowEntry.outPort().value());
801
802 forwardMatchDst.setInputPort(flowEntry.inPort().value());
803 forwardFlowModDst.setMatch(forwardMatchDst);
804 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
805 .setPort(flowEntry.outPort().value());
806
807 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
808 reverseFlowModSrc.setMatch(reverseMatchSrc);
809 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
810 .setPort(flowEntry.inPort().value());
811
812 reverseMatchDst.setInputPort(flowEntry.outPort().value());
813 reverseFlowModDst.setMatch(reverseMatchDst);
814 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
815 .setPort(flowEntry.inPort().value());
816
817 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
818
819 //Hopefully the switch is there
820 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
821 msgList.add(forwardFlowModSrc);
822 msgList.add(forwardFlowModDst);
823 msgList.add(reverseFlowModSrc);
824 msgList.add(reverseFlowModDst);
825
826 try {
827 sw.write(msgList, null);
828 sw.flush();
829 } catch (IOException e) {
830 log.error("Failure writing flow mod", e);
831 }
832 }
833 }
834 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200835
836 private void beginRouting(){
837 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200838 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200839 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200840
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200841 //Traverse ptree and create flows for all routes
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200842 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
843 if (node.rib != null){
844 prefixAdded(node);
845 }
846 }
847 }
848
849 private void checkSwitchesConnected(){
850 for (String dpid : switches){
851 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
852 log.debug("Not all switches are here yet");
853 return;
854 }
855 }
856 switchesConnected = true;
857 }
858
Jonathan Hartc824ad02013-07-03 15:58:45 +1200859 //Actually we only need to go half way round to verify full mesh connectivity
860 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200861 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200862 for (Interface dstInterface : interfaces.values()) {
863 for (Interface srcInterface : interfaces.values()) {
864 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200865 continue;
866 }
867
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200868 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200869 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200870
871 if (shortestPath == null){
872 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200873 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200874 return;
875 }
876 }
877 }
878 topologyReady = true;
879 }
880
881 private void checkStatus(){
882 log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
883
884 if (!switchesConnected){
885 checkSwitchesConnected();
886 }
887 boolean oldTopologyReadyStatus = topologyReady;
888 if (switchesConnected && !topologyReady){
889 checkTopologyReady();
890 }
891 if (!oldTopologyReadyStatus && topologyReady){
892 beginRouting();
893 }
894 }
895
pingping-lina2cbfad2013-03-07 08:39:21 +0800896 @Override
897 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +0800898 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200899 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700900 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +0800901
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200902 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
903
Jonathan Hart61ba9372013-05-19 20:10:29 -0700904 //Retrieve the RIB from BGPd during startup
905 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800906 }
907
908 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200909 public void topologyChanged() {
910 //There seems to be more topology events than there should be. Lots of link
911 //updated, port up and switch updated on what should be a fairly static topology
pingping-lina2cbfad2013-03-07 08:39:21 +0800912
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200913 boolean refreshNeeded = false;
914 for (LDUpdate ldu : topology.getLastLinkUpdates()){
915 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
916 //We don't need to recalculate anything for just link updates
917 //They happen way too frequently (may be a bug in our link discovery)
918 refreshNeeded = true;
919 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200920
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200921 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +1200922
Jonathan Hart98957bf2013-07-01 14:49:24 +1200923 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
924 synchronized (linkUpdates) {
925 linkUpdates.add(ldu);
926 }
927 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200928 }
929
930 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200931 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +0800932 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200933 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800934
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200935 //TODO determine whether we need to listen for switch joins
936 @Override
937 public void addedSwitch(IOFSwitch sw) {
938 //checkStatus();
939 }
940
941 @Override
942 public void removedSwitch(IOFSwitch sw) {
943 // TODO Auto-generated method stub
944 }
945
946 @Override
947 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200948
949 @Override
950 public String getName() {
951 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +0800952 }
953}