blob: 20341185a378d61c72002a47533c26ce17b1e642 [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;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070038import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070039import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120040import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070041import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070042import net.onrc.onos.ofcontroller.util.Port;
43import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080044import net.sf.json.JSONArray;
45import net.sf.json.JSONObject;
46import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080047
Jonathan Hartd1f23252013-06-13 15:17:05 +120048import org.codehaus.jackson.JsonParseException;
49import org.codehaus.jackson.map.JsonMappingException;
50import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070051import org.openflow.protocol.OFFlowMod;
52import org.openflow.protocol.OFMatch;
53import org.openflow.protocol.OFMessage;
54import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120055import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070056import 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 Hart1236a9b2013-06-18 22:10:05 +120064public class BgpRoute implements IFloodlightModule, IBgpRouteService,
65 ITopologyListener, IOFSwitchListener {
pingping-lina2cbfad2013-03-07 08:39:21 +080066
67 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
68
69 protected IFloodlightProviderService floodlightProvider;
70 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070071 protected ITopoRouteService topoRouteService;
72 protected IDeviceService devices;
73 protected IRestApiService restApi;
74
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120075 protected ProxyArpManager proxyArp;
76
pingping-lina2cbfad2013-03-07 08:39:21 +080077 protected static Ptree ptree;
Jonathan Hart61ba9372013-05-19 20:10:29 -070078 protected String bgpdRestIp;
79 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120080 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070081
82 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
83 //the controller/OS should hand out cookie IDs to prevent conflicts.
84 protected final long APP_COOKIE = 0xa0000000000000L;
85 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
86 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
87 //Cookie for flows in ingress switches that rewrite the MAC address
88 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120089 //Cookie for flows that setup BGP paths
90 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +120091 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
92 //need to be higher priority than this otherwise the rewrite may not get done
93 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070094
Jonathan Hart832a7cb2013-06-24 11:25:35 +120095 protected final short BGP_PORT = 179;
96
Jonathan Hart98957bf2013-07-01 14:49:24 +120097 protected final int TOPO_DETECTION_WAIT = 2; //seconds
98
Jonathan Hart832a7cb2013-06-24 11:25:35 +120099 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200100 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200101 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200102 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200103 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200104
105 //True when all switches have connected
106 protected volatile boolean switchesConnected = false;
107 //True when we have a full mesh of shortest paths between gateways
108 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200109
Jonathan Hart98957bf2013-07-01 14:49:24 +1200110 protected ArrayList<LDUpdate> linkUpdates;
111 protected SingletonTask topologyChangeDetectorTask;
112
Jonathan Hart98957bf2013-07-01 14:49:24 +1200113 protected class TopologyChangeDetector implements Runnable {
114 @Override
115 public void run() {
116 log.debug("Running topology change detection task");
117 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200118 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200119 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
120
121 List<Link> activeLinks = topoLinkService.getActiveLinks();
122 for (Link l : activeLinks){
123 log.debug("active link: {}", l);
124 }
125
126 Iterator<LDUpdate> it = linkUpdates.iterator();
127 while (it.hasNext()){
128 LDUpdate ldu = it.next();
129 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
130 ldu.getDst(), ldu.getDstPort());
131
132 if (activeLinks.contains(l)){
133 log.debug("Not found: {}", l);
134 it.remove();
135 }
136 }
137 }
138
139 if (linkUpdates.isEmpty()){
140 //All updates have been seen in network map.
141 //We can check if topology is ready
142 log.debug("No know changes outstanding. Checking topology now");
143 checkStatus();
144 }
145 else {
146 //We know of some link updates that haven't propagated to the database yet
147 log.debug("Some changes not found in network map- size {}", linkUpdates.size());
148 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
149 }
150 }
151 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700152
Jonathan Hartd1f23252013-06-13 15:17:05 +1200153 private void readGatewaysConfiguration(String gatewaysFilename){
154 File gatewaysFile = new File(gatewaysFilename);
155 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700156
Jonathan Hartd1f23252013-06-13 15:17:05 +1200157 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200158 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
159
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200160 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200161 interfaces = new HashMap<String, Interface>();
162 for (Interface intf : config.getInterfaces()){
163 interfaces.put(intf.getName(), intf);
164 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200165 bgpPeers = new HashMap<InetAddress, BgpPeer>();
166 for (BgpPeer peer : config.getPeers()){
167 bgpPeers.put(peer.getIpAddress(), peer);
168 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200169
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200170 bgpdAttachmentPoint = new SwitchPort(
171 new Dpid(config.getBgpdAttachmentDpid()),
172 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200173
Jonathan Hartd1f23252013-06-13 15:17:05 +1200174 } catch (JsonParseException e) {
175 log.error("Error in JSON file", e);
176 System.exit(1);
177 } catch (JsonMappingException e) {
178 log.error("Error in JSON file", e);
179 System.exit(1);
180 } catch (IOException e) {
181 log.error("Error reading JSON file", e);
182 System.exit(1);
183 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700184 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800185
186 @Override
187 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700188 Collection<Class<? extends IFloodlightService>> l
189 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800190 l.add(IBgpRouteService.class);
191 return l;
192 }
193
194 @Override
195 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700196 Map<Class<? extends IFloodlightService>, IFloodlightService> m
197 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800198 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800199 return m;
200 }
201
pingping-lina2cbfad2013-03-07 08:39:21 +0800202 @Override
203 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700204 Collection<Class<? extends IFloodlightService>> l
205 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800206 l.add(IFloodlightProviderService.class);
207 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700208 l.add(IDeviceService.class);
209 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800210 return l;
211 }
212
213 @Override
214 public void init(FloodlightModuleContext context)
215 throws FloodlightModuleException {
216
217 ptree = new Ptree(32);
Jonathan Hartc824ad02013-07-03 15:58:45 +1200218
pingping-lina2cbfad2013-03-07 08:39:21 +0800219 // Register floodlight provider and REST handler.
220 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800221 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700222 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200223 restApi = context.getServiceImpl(IRestApiService.class);
224
225 //TODO We'll initialise this here for now, but it should really be done as
226 //part of the controller core
227 proxyArp = new ProxyArpManager(floodlightProvider, topology);
pingping-lina2cbfad2013-03-07 08:39:21 +0800228
Jonathan Hart98957bf2013-07-01 14:49:24 +1200229 linkUpdates = new ArrayList<LDUpdate>();
230 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
231 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700232
233 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200234
Jonathan Hart61ba9372013-05-19 20:10:29 -0700235 //Read in config values
236 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
237 if (bgpdRestIp == null){
238 log.error("BgpdRestIp property not found in config file");
239 System.exit(1);
240 }
241 else {
242 log.info("BgpdRestIp set to {}", bgpdRestIp);
243 }
244
245 routerId = context.getConfigParams(this).get("RouterId");
246 if (routerId == null){
247 log.error("RouterId property not found in config file");
248 System.exit(1);
249 }
250 else {
251 log.info("RouterId set to {}", routerId);
252 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200253
Jonathan Hart9575cb62013-07-05 13:43:49 +1200254 String configFilenameParameter = context.getConfigParams(this).get("configfile");
255 if (configFilenameParameter != null){
256 configFilename = configFilenameParameter;
257 }
258 log.debug("Config file set to {}", configFilename);
259
260 readGatewaysConfiguration(configFilename);
pingping-lina2cbfad2013-03-07 08:39:21 +0800261 // Test.
262 //test();
263 }
264
265 public Ptree getPtree() {
266 return ptree;
267 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700268
269 public void clearPtree() {
270 //ptree = null;
271 ptree = new Ptree(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800272 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700273
pingping-line2a09ca2013-03-23 09:33:58 +0800274 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700275 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800276 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700277
pingping-line2a09ca2013-03-23 09:33:58 +0800278 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700279 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800280 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800281
282 // Return nexthop address as byte array.
283 public Rib lookupRib(byte[] dest) {
284 if (ptree == null) {
285 log.debug("lookupRib: ptree null");
286 return null;
287 }
288
289 PtreeNode node = ptree.match(dest, 32);
290 if (node == null) {
291 log.debug("lookupRib: ptree node null");
292 return null;
293 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700294
pingping-lina2cbfad2013-03-07 08:39:21 +0800295 if (node.rib == null) {
296 log.debug("lookupRib: ptree rib null");
297 return null;
298 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700299
pingping-lina2cbfad2013-03-07 08:39:21 +0800300 ptree.delReference(node);
301
302 return node.rib;
303 }
304
Jonathan Hart61ba9372013-05-19 20:10:29 -0700305 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800306 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700307 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800308 System.out.println("Here it is");
309 Prefix p = new Prefix("128.0.0.0", 8);
310 Prefix q = new Prefix("8.0.0.0", 8);
311 Prefix r = new Prefix("10.0.0.0", 24);
312 Prefix a = new Prefix("10.0.0.1", 32);
313
314 ptree.acquire(p.getAddress(), p.masklen);
315 ptree.acquire(q.getAddress(), q.masklen);
316 ptree.acquire(r.getAddress(), r.masklen);
317
318 System.out.println("Traverse start");
319 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
320 Prefix p_result = new Prefix(node.key, node.keyBits);
321 }
322
323 PtreeNode n = ptree.match(a.getAddress(), a.masklen);
324 if (n != null) {
325 System.out.println("Matched prefix for 10.0.0.1:");
326 Prefix x = new Prefix(n.key, n.keyBits);
327 ptree.delReference(n);
328 }
329
330 n = ptree.lookup(p.getAddress(), p.masklen);
331 if (n != null) {
332 ptree.delReference(n);
333 ptree.delReference(n);
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 n = ptree.lookup(q.getAddress(), q.masklen);
341 if (n != null) {
342 ptree.delReference(n);
343 ptree.delReference(n);
344 }
345 System.out.println("Traverse start");
346 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
347 Prefix p_result = new Prefix(node.key, node.keyBits);
348 }
349
350 n = ptree.lookup(r.getAddress(), r.masklen);
351 if (n != null) {
352 ptree.delReference(n);
353 ptree.delReference(n);
354 }
355 System.out.println("Traverse start");
356 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
357 Prefix p_result = new Prefix(node.key, node.keyBits);
358 }
359
360 }
361
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200362 private String getPrefixFromPtree(PtreeNode node){
363 InetAddress address = null;
364 try {
365 address = InetAddress.getByAddress(node.key);
366 } catch (UnknownHostException e1) {
367 //Should never happen is the reverse conversion has already been done
368 log.error("Malformed IP address");
369 return "";
370 }
371 return address.toString() + "/" + node.rib.masklen;
372 }
373
Jonathan Hart61ba9372013-05-19 20:10:29 -0700374 private void retrieveRib(){
375 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
376 String response = RestClient.get(url);
377
378 if (response.equals("")){
379 return;
380 }
381
382 response = response.replaceAll("\"", "'");
383 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
384 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
385 String router_id = jsonObj.getString("router-id");
386
387 int size = rib_json_array.size();
388
389 log.info("Retrived RIB of {} entries from BGPd", size);
390
391 for (int j = 0; j < size; j++) {
392 JSONObject second_json_object = rib_json_array.getJSONObject(j);
393 String prefix = second_json_object.getString("prefix");
394 String nexthop = second_json_object.getString("nexthop");
395
396 //insert each rib entry into the local rib;
397 String[] substring = prefix.split("/");
398 String prefix1 = substring[0];
399 String mask1 = substring[1];
400
401 Prefix p;
402 try {
403 p = new Prefix(prefix1, Integer.valueOf(mask1));
404 } catch (NumberFormatException e) {
405 log.warn("Wrong mask format in RIB JSON: {}", mask1);
406 continue;
407 } catch (UnknownHostException e1) {
408 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
409 continue;
410 }
411
412 PtreeNode node = ptree.acquire(p.getAddress(), p.masklen);
413 Rib rib = new Rib(router_id, nexthop, p.masklen);
414
415 if (node.rib != null) {
416 node.rib = null;
417 ptree.delReference(node);
418 }
419
420 node.rib = rib;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700421
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200422 prefixAdded(node);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700423 }
424 }
425
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200426 public void prefixAdded(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200427 if (!topologyReady){
428 return;
429 }
430
431 String prefix = getPrefixFromPtree(node);
432
Jonathan Hartc824ad02013-07-03 15:58:45 +1200433 log.debug("New prefix {} added, next hop {}, routerId {}",
434 new Object[] {prefix, node.rib.nextHop.toString(),
435 node.rib.routerId.getHostAddress()});
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200436
Jonathan Hartc824ad02013-07-03 15:58:45 +1200437 //TODO this is wrong, we shouldn't be dealing with BGP peers here.
438 //We need to figure out where the device is attached and what it's
439 //mac address is by learning.
440 //The next hop is not necessarily the peer, and the peer's attachment
441 //point is not necessarily the next hop's attachment point.
442 BgpPeer peer = bgpPeers.get(node.rib.nextHop);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700443
Jonathan Hartc824ad02013-07-03 15:58:45 +1200444 if (peer == null){
445 //TODO local router isn't in peers list so this will get thrown
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200446 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
Jonathan Hartc824ad02013-07-03 15:58:45 +1200447
448 //The other scenario is this is a route server route. In that
449 //case the next hop is not in our configuration
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200450 log.error("Couldn't find next hop router in router {} in config"
451 , node.rib.nextHop.toString());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700452 return; //just quit out here? This is probably a configuration error
453 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200454
455 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200456
Jonathan Hartc824ad02013-07-03 15:58:45 +1200457 //Add a flow to rewrite mac for this prefix to all border switches
458 for (Interface srcInterface : interfaces.values()) {
459 if (srcInterface == peerInterface) {
460 //Don't push a flow for the switch where this peer is attached
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700461 continue;
462 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200463
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700464 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200465 srcInterface.getSwitchPort(),
466 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700467
468 if (shortestPath == null){
469 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200470 srcInterface.getSwitchPort(),
471 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700472 return; // just quit here?
473 }
474
475 //TODO check the shortest path against the cached version we
476 //calculated before. If they don't match up that's a problem
477
478 //Set up the flow mod
479 OFFlowMod fm =
480 (OFFlowMod) floodlightProvider.getOFMessageFactory()
481 .getMessage(OFType.FLOW_MOD);
482
483 fm.setIdleTimeout((short)0)
484 .setHardTimeout((short)0)
485 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
486 .setCookie(MAC_RW_COOKIE)
487 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200488 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700489 .setLengthU(OFFlowMod.MINIMUM_LENGTH
490 + OFActionDataLayerDestination.MINIMUM_LENGTH
491 + OFActionOutput.MINIMUM_LENGTH);
492
493 OFMatch match = new OFMatch();
494 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200495 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700496
Jonathan Hartc824ad02013-07-03 15:58:45 +1200497 //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
498 //match.setDataLayerSource(peer.getMacAddress().toBytes());
499 //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200500
501 InetAddress address = null;
502 try {
503 address = InetAddress.getByAddress(node.key);
504 } catch (UnknownHostException e1) {
505 //Should never happen is the reverse conversion has already been done
506 log.error("Malformed IP address");
507 return;
508 }
509
510 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
511 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700512
513 //Set up MAC rewrite action
514 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200515 //TODO use ARP module rather than configured mac addresses
516 //TODO the peer's mac address is not necessarily the next hop's...
517 macRewriteAction.setDataLayerAddress(peer.getMacAddress().toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700518
519 //Set up output action
520 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200521 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700522
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200523 Port outputPort = shortestPath.flowEntries().get(0).outPort();
524 outputAction.setPort(outputPort.value());
525
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700526 List<OFAction> actions = new ArrayList<OFAction>();
527 actions.add(macRewriteAction);
528 actions.add(outputAction);
529 fm.setActions(actions);
530
531 //Write to switch
532 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200533 .get(srcInterface.getDpid());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700534
535 if (sw == null){
536 log.warn("Switch not found when pushing flow mod");
537 continue;
538 }
539
540 List<OFMessage> msglist = new ArrayList<OFMessage>();
541 msglist.add(fm);
542 try {
543 sw.write(msglist, null);
544 sw.flush();
545 } catch (IOException e) {
546 log.error("Failure writing flow mod", e);
547 }
548 }
549 }
550
Jonathan Hartc824ad02013-07-03 15:58:45 +1200551 //TODO this is largely untested
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200552 public void prefixDeleted(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200553 if (!topologyReady) {
554 return;
555 }
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200556
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200557 String prefix = getPrefixFromPtree(node);
558
559 log.debug("Prefix {} deleted, next hop {}",
560 prefix, node.rib.nextHop.toString());
561
562 //Remove MAC rewriting flows from other border switches
Jonathan Hartc824ad02013-07-03 15:58:45 +1200563 BgpPeer peer = bgpPeers.get(node.rib.nextHop);
564 if (peer == null){
565 //either a router server route or local route. Can't handle right now
566 return;
567 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200568
Jonathan Hartc824ad02013-07-03 15:58:45 +1200569 Interface peerInterface = interfaces.get(peer.getInterfaceName());
570
571 for (Interface srcInterface : interfaces.values()) {
572 if (srcInterface == peerInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200573 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)
Jonathan Hart9575cb62013-07-05 13:43:49 +1200586 .setOutPort(OFPort.OFPP_NONE)
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200587 .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
Jonathan Hartc824ad02013-07-03 15:58:45 +1200596 //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
597 //match.setDataLayerSource(peer.getMacAddress().toBytes());
598 //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200599
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()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200614 .get(srcInterface.getDpid());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200615
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 //For each border router, calculate and install a path from every other
638 //border switch to said border router. However, don't install the entry
639 //in to the first hop switch, as we need to install an entry to rewrite
640 //for each prefix received. This will be done later when prefixes have
641 //actually been received.
642
Jonathan Hartc824ad02013-07-03 15:58:45 +1200643 for (BgpPeer peer : bgpPeers.values()) {
644 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart9575cb62013-07-05 13:43:49 +1200645 //for (Map.Entry<String, Interface> intfEntry : interfaces.entrySet()) {
646 for (Interface srcInterface : interfaces.values()) {
647 //Interface srcInterface = intfEntry.getValue();
648 //if (peer.getInterfaceName().equals(intfEntry.getKey())){
649 if (peer.getInterfaceName().equals(srcInterface.getName())){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700650 continue;
651 }
652
653 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200654 srcInterface.getSwitchPort(), peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700655
656 if (shortestPath == null){
657 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200658 srcInterface.getSwitchPort(), peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700659 return; // just quit here?
660 }
661
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700662 //install flows
Jonathan Hartc824ad02013-07-03 15:58:45 +1200663 installPath(shortestPath.flowEntries(), peer);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700664 }
665 }
666 }
667
Jonathan Hartc824ad02013-07-03 15:58:45 +1200668 private void installPath(List<FlowEntry> flowEntries, BgpPeer peer){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700669 //Set up the flow mod
670 OFFlowMod fm =
671 (OFFlowMod) floodlightProvider.getOFMessageFactory()
672 .getMessage(OFType.FLOW_MOD);
673
674 OFActionOutput action = new OFActionOutput();
675 action.setMaxLength((short)0xffff);
676 List<OFAction> actions = new ArrayList<OFAction>();
677 actions.add(action);
678
679 fm.setIdleTimeout((short)0)
680 .setHardTimeout((short)0)
681 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
682 .setCookie(L2_FWD_COOKIE)
683 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700684 .setActions(actions)
685 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
686
687 //Don't push the first flow entry. We need to push entries in the
688 //first switch based on IP prefix which we don't know yet.
689 for (int i = 1; i < flowEntries.size(); i++){
690 FlowEntry flowEntry = flowEntries.get(i);
691
692 OFMatch match = new OFMatch();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200693 //TODO Again using MAC address from configuration
694 match.setDataLayerDestination(peer.getMacAddress().toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700695 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
696 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
697
698 fm.setMatch(match);
699
700 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
701
702 if (sw == null){
703 log.warn("Switch not found when pushing flow mod");
704 continue;
705 }
706
707 List<OFMessage> msglist = new ArrayList<OFMessage>();
708 msglist.add(fm);
709 try {
710 sw.write(msglist, null);
711 sw.flush();
712 } catch (IOException e) {
713 log.error("Failure writing flow mod", e);
714 }
715
716 try {
717 fm = fm.clone();
718 } catch (CloneNotSupportedException e1) {
719 log.error("Failure cloning flow mod", e1);
720 }
721 }
722 }
723
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200724 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200725 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200726 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
727
728 DataPath path = topoRouteService.getShortestPath(
729 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
730
731 if (path == null){
732 log.debug("Unable to compute path for BGP traffic for {}",
733 bgpPeer.getIpAddress());
734 continue;
735 }
736
737 //Set up the flow mod
738 OFFlowMod fm =
739 (OFFlowMod) floodlightProvider.getOFMessageFactory()
740 .getMessage(OFType.FLOW_MOD);
741
742 OFActionOutput action = new OFActionOutput();
743 action.setMaxLength((short)0xffff);
744 List<OFAction> actions = new ArrayList<OFAction>();
745 actions.add(action);
746
747 fm.setIdleTimeout((short)0)
748 .setHardTimeout((short)0)
749 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
750 .setCookie(BGP_COOKIE)
751 .setCommand(OFFlowMod.OFPFC_ADD)
752 .setPriority(SDNIP_PRIORITY)
753 .setActions(actions)
754 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
755
756 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
757 OFMatch forwardMatchSrc = new OFMatch();
758
759
760 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
761 + "/32";
762 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
763 + "/32";
764
765 //Common match fields
766 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
767 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
768 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
769 forwardMatchSrc.setTransportDestination(BGP_PORT);
770 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
771 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
772
773
774 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
775
776 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
777 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
778
779 OFMatch forwardMatchDst = forwardMatchSrc.clone();
780
781 forwardMatchSrc.setTransportSource(BGP_PORT);
782 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
783 forwardMatchDst.setTransportDestination(BGP_PORT);
784 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
785
786 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
787 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
788
789 OFMatch reverseMatchDst = reverseMatchSrc.clone();
790
791 reverseMatchSrc.setTransportSource(BGP_PORT);
792 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
793 reverseMatchDst.setTransportDestination(BGP_PORT);
794 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
795
796 fm.setMatch(forwardMatchSrc);
797
798 for (FlowEntry flowEntry : path.flowEntries()){
799 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
800 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
801 try {
802 forwardFlowModSrc = fm.clone();
803 forwardFlowModDst = fm.clone();
804 reverseFlowModSrc = fm.clone();
805 reverseFlowModDst = fm.clone();
806 } catch (CloneNotSupportedException e) {
807 log.warn("Clone failed", e);
808 continue;
809 }
810
811 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
812 forwardFlowModSrc.setMatch(forwardMatchSrc);
813 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
814 .setPort(flowEntry.outPort().value());
815
816 forwardMatchDst.setInputPort(flowEntry.inPort().value());
817 forwardFlowModDst.setMatch(forwardMatchDst);
818 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
819 .setPort(flowEntry.outPort().value());
820
821 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
822 reverseFlowModSrc.setMatch(reverseMatchSrc);
823 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
824 .setPort(flowEntry.inPort().value());
825
826 reverseMatchDst.setInputPort(flowEntry.outPort().value());
827 reverseFlowModDst.setMatch(reverseMatchDst);
828 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
829 .setPort(flowEntry.inPort().value());
830
831 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
832
833 //Hopefully the switch is there
834 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
835 msgList.add(forwardFlowModSrc);
836 msgList.add(forwardFlowModDst);
837 msgList.add(reverseFlowModSrc);
838 msgList.add(reverseFlowModDst);
839
840 try {
841 sw.write(msgList, null);
842 sw.flush();
843 } catch (IOException e) {
844 log.error("Failure writing flow mod", e);
845 }
846 }
847 }
848 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200849
850 private void beginRouting(){
851 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200852 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200853 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200854
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200855 //Traverse ptree and create flows for all routes
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200856 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
857 if (node.rib != null){
858 prefixAdded(node);
859 }
860 }
861 }
862
863 private void checkSwitchesConnected(){
864 for (String dpid : switches){
865 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
866 log.debug("Not all switches are here yet");
867 return;
868 }
869 }
870 switchesConnected = true;
871 }
872
Jonathan Hartc824ad02013-07-03 15:58:45 +1200873 //Actually we only need to go half way round to verify full mesh connectivity
874 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200875 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200876 for (Interface dstInterface : interfaces.values()) {
877 for (Interface srcInterface : interfaces.values()) {
878 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200879 continue;
880 }
881
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200882 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200883 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200884
885 if (shortestPath == null){
886 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200887 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200888 return;
889 }
890 }
891 }
892 topologyReady = true;
893 }
894
895 private void checkStatus(){
896 log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
897
898 if (!switchesConnected){
899 checkSwitchesConnected();
900 }
901 boolean oldTopologyReadyStatus = topologyReady;
902 if (switchesConnected && !topologyReady){
903 checkTopologyReady();
904 }
905 if (!oldTopologyReadyStatus && topologyReady){
906 beginRouting();
907 }
908 }
909
pingping-lina2cbfad2013-03-07 08:39:21 +0800910 @Override
911 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +0800912 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200913 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700914 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +0800915
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200916 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
917
Jonathan Hart61ba9372013-05-19 20:10:29 -0700918 //Retrieve the RIB from BGPd during startup
919 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800920 }
921
922 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200923 public void topologyChanged() {
924 //There seems to be more topology events than there should be. Lots of link
925 //updated, port up and switch updated on what should be a fairly static topology
pingping-lina2cbfad2013-03-07 08:39:21 +0800926
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200927 boolean refreshNeeded = false;
928 for (LDUpdate ldu : topology.getLastLinkUpdates()){
929 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
930 //We don't need to recalculate anything for just link updates
931 //They happen way too frequently (may be a bug in our link discovery)
932 refreshNeeded = true;
933 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200934
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200935 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +1200936
Jonathan Hart98957bf2013-07-01 14:49:24 +1200937 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
938 synchronized (linkUpdates) {
939 linkUpdates.add(ldu);
940 }
941 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200942 }
943
944 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200945 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +0800946 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200947 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800948
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200949 //TODO determine whether we need to listen for switch joins
950 @Override
951 public void addedSwitch(IOFSwitch sw) {
952 //checkStatus();
953 }
954
955 @Override
956 public void removedSwitch(IOFSwitch sw) {
957 // TODO Auto-generated method stub
958 }
959
960 @Override
961 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200962
963 @Override
964 public String getName() {
965 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +0800966 }
967}