blob: c978d44a995b989719f5ab93e63219ba9711f818 [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;
pingping-lina2cbfad2013-03-07 08:39:21 +08006import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07007import java.util.Collection;
pingping-lina2cbfad2013-03-07 08:39:21 +08008import java.util.HashMap;
Jonathan Hart98957bf2013-07-01 14:49:24 +12009import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070010import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070011import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120012import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120013import java.util.concurrent.BlockingQueue;
14import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120015import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120016import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080019
Jonathan Hart61ba9372013-05-19 20:10:29 -070020import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070021import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120022import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120027import net.floodlightcontroller.core.util.SingletonTask;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070028import net.floodlightcontroller.devicemanager.IDeviceService;
29import net.floodlightcontroller.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120030import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080031import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120032import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080033import net.floodlightcontroller.topology.ITopologyListener;
34import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120035import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120036import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
Jonathan Hart98957bf2013-07-01 14:49:24 +120037import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070038import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120039import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070040import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
41import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120042import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120043import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070044import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070045import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120046import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070048import net.onrc.onos.ofcontroller.util.Port;
49import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080050import net.sf.json.JSONArray;
51import net.sf.json.JSONObject;
52import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080053
Jonathan Hartd1f23252013-06-13 15:17:05 +120054import org.codehaus.jackson.JsonParseException;
55import org.codehaus.jackson.map.JsonMappingException;
56import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070057import org.openflow.protocol.OFFlowMod;
58import org.openflow.protocol.OFMatch;
59import org.openflow.protocol.OFMessage;
60import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120061import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070062import org.openflow.protocol.OFType;
63import org.openflow.protocol.action.OFAction;
64import org.openflow.protocol.action.OFActionDataLayerDestination;
65import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120066import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080067import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
69
Jonathan Hart4dfc3652013-08-02 20:22:36 +120070import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120071import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120072import com.google.common.collect.Multimaps;
73import com.google.common.collect.SetMultimap;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120074import com.google.common.util.concurrent.ThreadFactoryBuilder;
75
Jonathan Hart1236a9b2013-06-18 22:10:05 +120076public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart4dfc3652013-08-02 20:22:36 +120077 ITopologyListener, IOFSwitchListener,
78 IArpRequester {
pingping-lina2cbfad2013-03-07 08:39:21 +080079
80 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
81
82 protected IFloodlightProviderService floodlightProvider;
83 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070084 protected ITopoRouteService topoRouteService;
85 protected IDeviceService devices;
86 protected IRestApiService restApi;
87
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120088 protected ProxyArpManager proxyArp;
89
Jonathan Hartd7e158d2013-08-07 23:04:48 +120090 //protected static Ptree ptree;
Jonathan Hart29b972d2013-08-12 23:43:51 +120091 protected IPatriciaTrie<RibEntry> ptree;
Jonathan Hartabf10222013-08-13 10:19:34 +120092 protected IPatriciaTrie<Interface> interfacePtrie;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120093 protected BlockingQueue<RibUpdate> ribUpdates;
94
Jonathan Hart61ba9372013-05-19 20:10:29 -070095 protected String bgpdRestIp;
96 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120097 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070098
99 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
100 //the controller/OS should hand out cookie IDs to prevent conflicts.
101 protected final long APP_COOKIE = 0xa0000000000000L;
102 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
103 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
104 //Cookie for flows in ingress switches that rewrite the MAC address
105 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200106 //Cookie for flows that setup BGP paths
107 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200108 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
109 //need to be higher priority than this otherwise the rewrite may not get done
110 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700111
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200112 protected final short BGP_PORT = 179;
113
Jonathan Hart98957bf2013-07-01 14:49:24 +1200114 protected final int TOPO_DETECTION_WAIT = 2; //seconds
115
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200116 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200117 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200118 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200119 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200120 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200121
122 //True when all switches have connected
123 protected volatile boolean switchesConnected = false;
124 //True when we have a full mesh of shortest paths between gateways
125 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200126
Jonathan Hart98957bf2013-07-01 14:49:24 +1200127 protected ArrayList<LDUpdate> linkUpdates;
128 protected SingletonTask topologyChangeDetectorTask;
129
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200130 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
131 protected SetMultimap<InetAddress, PathUpdate> pathsWaitingOnArp;
132
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200133 protected ExecutorService bgpUpdatesExecutor;
134
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200135 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
136
137 private class PushedFlowMod {
138 private long dpid;
139 private OFFlowMod flowMod;
140
141 public PushedFlowMod(long dpid, OFFlowMod flowMod) {
142 this.dpid = dpid;
143 this.flowMod = flowMod;
144 }
145
146 public long getDpid() {
147 return dpid;
148 }
149
150 public OFFlowMod getFlowMod() {
151 return flowMod;
152 }
153 }
154
Jonathan Hart98957bf2013-07-01 14:49:24 +1200155 protected class TopologyChangeDetector implements Runnable {
156 @Override
157 public void run() {
158 log.debug("Running topology change detection task");
159 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200160 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200161 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
162
163 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200164
165 Iterator<LDUpdate> it = linkUpdates.iterator();
166 while (it.hasNext()){
167 LDUpdate ldu = it.next();
168 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
169 ldu.getDst(), ldu.getDstPort());
170
171 if (activeLinks.contains(l)){
172 log.debug("Not found: {}", l);
173 it.remove();
174 }
175 }
176 }
177
178 if (linkUpdates.isEmpty()){
179 //All updates have been seen in network map.
180 //We can check if topology is ready
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200181 log.debug("No known changes outstanding. Checking topology now");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200182 checkStatus();
183 }
184 else {
185 //We know of some link updates that haven't propagated to the database yet
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200186 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200187 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
188 }
189 }
190 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700191
Jonathan Hartd1f23252013-06-13 15:17:05 +1200192 private void readGatewaysConfiguration(String gatewaysFilename){
193 File gatewaysFile = new File(gatewaysFilename);
194 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700195
Jonathan Hartd1f23252013-06-13 15:17:05 +1200196 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200197 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
198
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200199 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200200 interfaces = new HashMap<String, Interface>();
201 for (Interface intf : config.getInterfaces()){
202 interfaces.put(intf.getName(), intf);
203 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200204 bgpPeers = new HashMap<InetAddress, BgpPeer>();
205 for (BgpPeer peer : config.getPeers()){
206 bgpPeers.put(peer.getIpAddress(), peer);
207 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200208
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200209 bgpdAttachmentPoint = new SwitchPort(
210 new Dpid(config.getBgpdAttachmentDpid()),
211 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200212
Jonathan Hartd1f23252013-06-13 15:17:05 +1200213 } catch (JsonParseException e) {
214 log.error("Error in JSON file", e);
215 System.exit(1);
216 } catch (JsonMappingException e) {
217 log.error("Error in JSON file", e);
218 System.exit(1);
219 } catch (IOException e) {
220 log.error("Error reading JSON file", e);
221 System.exit(1);
222 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200223
224 //Populate the interface Patricia Trie
225 for (Interface intf : interfaces.values()) {
226 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
227 interfacePtrie.put(prefix, intf);
228 }
229
230 /*
231 Iterator<IPatriciaTrie.Entry<Interface>> it = interfacePtrie.iterator();
232 while (it.hasNext()) {
233 IPatriciaTrie.Entry<Interface> entry = it.next();
234 Interface intf = entry.getValue();
235 log.debug("Interface at prefix {}, switchport {}/{}",
236 new Object[] {entry.getPrefix(), HexString.toHexString(intf.getDpid()), intf.getPort()});
237 }
238 */
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700239 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800240
241 @Override
242 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700243 Collection<Class<? extends IFloodlightService>> l
244 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800245 l.add(IBgpRouteService.class);
246 return l;
247 }
248
249 @Override
250 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700251 Map<Class<? extends IFloodlightService>, IFloodlightService> m
252 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800253 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800254 return m;
255 }
256
pingping-lina2cbfad2013-03-07 08:39:21 +0800257 @Override
258 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700259 Collection<Class<? extends IFloodlightService>> l
260 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800261 l.add(IFloodlightProviderService.class);
262 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700263 l.add(IDeviceService.class);
264 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800265 return l;
266 }
267
268 @Override
269 public void init(FloodlightModuleContext context)
270 throws FloodlightModuleException {
271
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200272 //ptree = new Ptree(32);
Jonathan Hart29b972d2013-08-12 23:43:51 +1200273 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200274 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200275
276 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200277
pingping-lina2cbfad2013-03-07 08:39:21 +0800278 // Register floodlight provider and REST handler.
279 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800280 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700281 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200282 restApi = context.getServiceImpl(IRestApiService.class);
283
284 //TODO We'll initialise this here for now, but it should really be done as
285 //part of the controller core
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200286 proxyArp = new ProxyArpManager(floodlightProvider, topology, devices);
pingping-lina2cbfad2013-03-07 08:39:21 +0800287
Jonathan Hart98957bf2013-07-01 14:49:24 +1200288 linkUpdates = new ArrayList<LDUpdate>();
289 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
290 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700291
292 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200293
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200294 pathsWaitingOnArp = Multimaps.synchronizedSetMultimap(
295 HashMultimap.<InetAddress, PathUpdate>create());
296 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
297 HashMultimap.<InetAddress, RibUpdate>create());
298
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200299 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
300
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200301 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
302 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
303
Jonathan Hart61ba9372013-05-19 20:10:29 -0700304 //Read in config values
305 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
306 if (bgpdRestIp == null){
307 log.error("BgpdRestIp property not found in config file");
308 System.exit(1);
309 }
310 else {
311 log.info("BgpdRestIp set to {}", bgpdRestIp);
312 }
313
314 routerId = context.getConfigParams(this).get("RouterId");
315 if (routerId == null){
316 log.error("RouterId property not found in config file");
317 System.exit(1);
318 }
319 else {
320 log.info("RouterId set to {}", routerId);
321 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200322
Jonathan Hart9575cb62013-07-05 13:43:49 +1200323 String configFilenameParameter = context.getConfigParams(this).get("configfile");
324 if (configFilenameParameter != null){
325 configFilename = configFilenameParameter;
326 }
327 log.debug("Config file set to {}", configFilename);
328
329 readGatewaysConfiguration(configFilename);
pingping-lina2cbfad2013-03-07 08:39:21 +0800330 // Test.
331 //test();
332 }
333
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200334 //public Ptree getPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200335 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800336 return ptree;
337 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700338
339 public void clearPtree() {
340 //ptree = null;
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200341 //ptree = new Ptree(32);
Jonathan Hart29b972d2013-08-12 23:43:51 +1200342 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800343 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700344
pingping-line2a09ca2013-03-23 09:33:58 +0800345 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700346 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800347 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700348
pingping-line2a09ca2013-03-23 09:33:58 +0800349 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700350 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800351 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800352
353 // Return nexthop address as byte array.
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200354 /*
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200355 public RibEntry lookupRib(byte[] dest) {
pingping-lina2cbfad2013-03-07 08:39:21 +0800356 if (ptree == null) {
357 log.debug("lookupRib: ptree null");
358 return null;
359 }
360
361 PtreeNode node = ptree.match(dest, 32);
362 if (node == null) {
363 log.debug("lookupRib: ptree node null");
364 return null;
365 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700366
pingping-lina2cbfad2013-03-07 08:39:21 +0800367 if (node.rib == null) {
368 log.debug("lookupRib: ptree rib null");
369 return null;
370 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700371
pingping-lina2cbfad2013-03-07 08:39:21 +0800372 ptree.delReference(node);
373
374 return node.rib;
375 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200376 */
pingping-lina2cbfad2013-03-07 08:39:21 +0800377
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200378 /*
Jonathan Hart61ba9372013-05-19 20:10:29 -0700379 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800380 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700381 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800382 System.out.println("Here it is");
383 Prefix p = new Prefix("128.0.0.0", 8);
384 Prefix q = new Prefix("8.0.0.0", 8);
385 Prefix r = new Prefix("10.0.0.0", 24);
386 Prefix a = new Prefix("10.0.0.1", 32);
387
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200388 ptree.acquire(p.getAddress(), p.getPrefixLength());
389 ptree.acquire(q.getAddress(), q.getPrefixLength());
390 ptree.acquire(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800391
392 System.out.println("Traverse start");
393 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
394 Prefix p_result = new Prefix(node.key, node.keyBits);
395 }
396
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200397 PtreeNode n = ptree.match(a.getAddress(), a.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800398 if (n != null) {
399 System.out.println("Matched prefix for 10.0.0.1:");
400 Prefix x = new Prefix(n.key, n.keyBits);
401 ptree.delReference(n);
402 }
403
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200404 n = ptree.lookup(p.getAddress(), p.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800405 if (n != null) {
406 ptree.delReference(n);
407 ptree.delReference(n);
408 }
409 System.out.println("Traverse start");
410 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
411 Prefix p_result = new Prefix(node.key, node.keyBits);
412 }
413
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200414 n = ptree.lookup(q.getAddress(), q.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800415 if (n != null) {
416 ptree.delReference(n);
417 ptree.delReference(n);
418 }
419 System.out.println("Traverse start");
420 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
421 Prefix p_result = new Prefix(node.key, node.keyBits);
422 }
423
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200424 n = ptree.lookup(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800425 if (n != null) {
426 ptree.delReference(n);
427 ptree.delReference(n);
428 }
429 System.out.println("Traverse start");
430 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
431 Prefix p_result = new Prefix(node.key, node.keyBits);
432 }
433
434 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200435 */
pingping-lina2cbfad2013-03-07 08:39:21 +0800436
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200437 //TODO once the Ptree is object oriented this can go
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200438 /*
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200439 private String getPrefixFromPtree(PtreeNode node){
440 InetAddress address = null;
441 try {
442 address = InetAddress.getByAddress(node.key);
443 } catch (UnknownHostException e1) {
444 //Should never happen is the reverse conversion has already been done
445 log.error("Malformed IP address");
446 return "";
447 }
448 return address.toString() + "/" + node.rib.masklen;
449 }
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200450 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200451
Jonathan Hart61ba9372013-05-19 20:10:29 -0700452 private void retrieveRib(){
453 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
454 String response = RestClient.get(url);
455
456 if (response.equals("")){
457 return;
458 }
459
460 response = response.replaceAll("\"", "'");
461 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
462 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
463 String router_id = jsonObj.getString("router-id");
464
465 int size = rib_json_array.size();
466
467 log.info("Retrived RIB of {} entries from BGPd", size);
468
469 for (int j = 0; j < size; j++) {
470 JSONObject second_json_object = rib_json_array.getJSONObject(j);
471 String prefix = second_json_object.getString("prefix");
472 String nexthop = second_json_object.getString("nexthop");
473
474 //insert each rib entry into the local rib;
475 String[] substring = prefix.split("/");
476 String prefix1 = substring[0];
477 String mask1 = substring[1];
478
479 Prefix p;
480 try {
481 p = new Prefix(prefix1, Integer.valueOf(mask1));
482 } catch (NumberFormatException e) {
483 log.warn("Wrong mask format in RIB JSON: {}", mask1);
484 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200485 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700486 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
487 continue;
488 }
489
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200490 //PtreeNode node = ptree.acquire(p.getAddress(), p.getPrefixLength());
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200491 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700492
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200493 /*
Jonathan Hart61ba9372013-05-19 20:10:29 -0700494 if (node.rib != null) {
495 node.rib = null;
496 ptree.delReference(node);
497 }
498
499 node.rib = rib;
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200500 */
501
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200502 //ptree.put(p, rib);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700503
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200504 //addPrefixFlows(p, rib);
505 try {
506 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
507 } catch (InterruptedException e) {
508 log.debug("Interrupted while pushing onto update queue");
509 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700510 }
511 }
512
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200513 @Override
514 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200515 try {
516 ribUpdates.put(update);
517 } catch (InterruptedException e) {
518 // TODO Auto-generated catch block
519 log.debug(" ", e);
520 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200521 }
522
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200523 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200524 Prefix prefix = update.getPrefix();
525
Jonathan Hart9ea31212013-08-12 21:40:34 +1200526 log.debug("Processing prefix add {}", prefix);
527
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200528 //PtreeNode node = ptree.acquire(prefix.getAddress(), prefix.getPrefixLength());
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200529 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200530
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200531 //if (node.rib != null) {
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200532 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200533 //There was an existing nexthop for this prefix. This update supersedes that,
534 //so we need to remove the old flows for this prefix from the switches
535 deletePrefixFlows(prefix);
536
537 //Then remove the old nexthop from the Ptree
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200538 //node.rib = null;
539 //ptree.delReference(node);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200540 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200541
542 //Put the new nexthop in the Ptree
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200543 //node.rib = update.getRibEntry();
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200544
Jonathan Hart2f740782013-08-04 00:49:21 +1200545 //Push flows for the new <prefix, nexthop>
Jonathan Hart2f740782013-08-04 00:49:21 +1200546 addPrefixFlows(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200547 }
548
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200549 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200550 Prefix prefix = update.getPrefix();
551
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200552 //PtreeNode node = ptree.lookup(prefix.getAddress(), prefix.getPrefixLength());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200553
554 /*
555 * Remove the flows from the switches before the rib is lost
556 * Theory: we could get a delete for a prefix not in the Ptree.
557 * This would result in a null node being returned. We could get a delete for
558 * a node that's not actually there, but is a aggregate node. This would result
559 * in a non-null node with a null rib. Only a non-null node with a non-null
560 * rib is an actual prefix in the Ptree.
561 */
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200562
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200563 /*
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200564 if (node != null && node.rib != null) {
565 if (update.getRibEntry().equals(node.rib)) {
566 node.rib = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200567 ptree.delReference(node);
568
Jonathan Hart2f740782013-08-04 00:49:21 +1200569 deletePrefixFlows(update.getPrefix());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200570 }
571 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200572 */
573
574 if (ptree.remove(prefix, update.getRibEntry())) {
575 /*
576 * Only delete flows if an entry was actually removed from the trie.
577 * If no entry was removed, the <prefix, nexthop> wasn't there so
578 * it's probably already been removed and we don't need to do anything
579 */
580 deletePrefixFlows(prefix);
581 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200582 }
583
Jonathan Hart2f740782013-08-04 00:49:21 +1200584 //TODO compatibility layer, used by beginRouting()
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200585 /*public void prefixAdded(PtreeNode node) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200586 Prefix prefix = null;
587 try {
588 prefix = new Prefix(node.key, node.rib.masklen);
Jonathan Hart32e18222013-08-07 22:05:42 +1200589 } catch (IllegalArgumentException e) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200590 log.error(" ", e);
591 }
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200592
Jonathan Hart2f740782013-08-04 00:49:21 +1200593 addPrefixFlows(prefix, node.rib);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200594 }*/
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200595
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200596 private void addPrefixFlows(Prefix prefix, RibEntry rib) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200597 if (!topologyReady){
598 return;
599 }
600
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200601 //TODO before we do anything, we have to check that the RIB entry is still in the
602 //Ptree because it could have been removed while we were waiting for ARP.
603 //I think we'll have to make prefixAdded and prefixDelete atomic as well
604 //to protect against the prefix getting deleted while where trying to add it
Jonathan Hart2f740782013-08-04 00:49:21 +1200605
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200606 log.debug("New prefix {} added, next hop {}",
607 prefix, rib.getNextHop().getHostAddress());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200608
Jonathan Hartc824ad02013-07-03 15:58:45 +1200609 //TODO this is wrong, we shouldn't be dealing with BGP peers here.
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200610 //We need to figure out where the device is attached and what its
Jonathan Hartc824ad02013-07-03 15:58:45 +1200611 //mac address is by learning.
612 //The next hop is not necessarily the peer, and the peer's attachment
613 //point is not necessarily the next hop's attachment point.
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200614 BgpPeer peer = bgpPeers.get(rib.getNextHop());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700615
Jonathan Hartc824ad02013-07-03 15:58:45 +1200616 if (peer == null){
617 //TODO local router isn't in peers list so this will get thrown
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200618 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
Jonathan Hartc824ad02013-07-03 15:58:45 +1200619
620 //The other scenario is this is a route server route. In that
621 //case the next hop is not in our configuration
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200622 log.error("Couldn't find next hop router in router {} in config",
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200623 rib.getNextHop().getHostAddress());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700624 return; //just quit out here? This is probably a configuration error
625 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200626
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200627 //Get MAC address for peer from the ARP module
628 //TODO separate out the 'ask for MAC' bit to another method
629 byte[] peerMacAddress = proxyArp.getMacAddress(peer.getIpAddress());
630 if (peerMacAddress == null) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200631 //A RibUpdate is still a nice way to package them up
632 prefixesWaitingOnArp.put(peer.getIpAddress(),
633 new RibUpdate(Operation.UPDATE, prefix, rib));
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200634 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
635 return;
636 }
637
Jonathan Hartc824ad02013-07-03 15:58:45 +1200638 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200639
Jonathan Hartc824ad02013-07-03 15:58:45 +1200640 //Add a flow to rewrite mac for this prefix to all border switches
641 for (Interface srcInterface : interfaces.values()) {
642 if (srcInterface == peerInterface) {
643 //Don't push a flow for the switch where this peer is attached
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700644 continue;
645 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200646
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700647 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200648 srcInterface.getSwitchPort(),
649 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700650
651 if (shortestPath == null){
652 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200653 srcInterface.getSwitchPort(),
654 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700655 return; // just quit here?
656 }
657
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700658 //Set up the flow mod
659 OFFlowMod fm =
660 (OFFlowMod) floodlightProvider.getOFMessageFactory()
661 .getMessage(OFType.FLOW_MOD);
662
663 fm.setIdleTimeout((short)0)
664 .setHardTimeout((short)0)
665 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
666 .setCookie(MAC_RW_COOKIE)
667 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200668 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700669 .setLengthU(OFFlowMod.MINIMUM_LENGTH
670 + OFActionDataLayerDestination.MINIMUM_LENGTH
671 + OFActionOutput.MINIMUM_LENGTH);
672
673 OFMatch match = new OFMatch();
674 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200675 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700676
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200677 /*
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200678 InetAddress address = null;
679 try {
Jonathan Hart2f740782013-08-04 00:49:21 +1200680 address = InetAddress.getByAddress(prefix.getAddress());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200681 } catch (UnknownHostException e1) {
682 //Should never happen is the reverse conversion has already been done
683 log.error("Malformed IP address");
684 return;
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200685 }*/
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200686
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200687 //match.setFromCIDR(address.getHostAddress() + "/" +
688 // prefix.getPrefixLength(), OFMatch.STR_NW_DST);
689 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200690 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700691
692 //Set up MAC rewrite action
693 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200694 //TODO the peer's mac address is not necessarily the next hop's...
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200695 macRewriteAction.setDataLayerAddress(peerMacAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700696
697 //Set up output action
698 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200699 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700700
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200701 Port outputPort = shortestPath.flowEntries().get(0).outPort();
702 outputAction.setPort(outputPort.value());
703
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700704 List<OFAction> actions = new ArrayList<OFAction>();
705 actions.add(macRewriteAction);
706 actions.add(outputAction);
707 fm.setActions(actions);
708
709 //Write to switch
710 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200711 .get(srcInterface.getDpid());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700712
713 if (sw == null){
714 log.warn("Switch not found when pushing flow mod");
715 continue;
716 }
717
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200718 //TODO if prefix Added/Deleted are synchronized this shouldn't have to be
Jonathan Hart2f740782013-08-04 00:49:21 +1200719 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200720
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700721 List<OFMessage> msglist = new ArrayList<OFMessage>();
722 msglist.add(fm);
723 try {
724 sw.write(msglist, null);
725 sw.flush();
726 } catch (IOException e) {
727 log.error("Failure writing flow mod", e);
728 }
729 }
730 }
731
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200732 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200733 //TODO check delete/add synchronization
Jonathan Hart2f740782013-08-04 00:49:21 +1200734
735 private void deletePrefixFlows(Prefix prefix) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200736 if (!topologyReady) {
737 return;
738 }
739
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200740 log.debug("In deletePrefixFlows for {}", prefix);
Jonathan Hart2f740782013-08-04 00:49:21 +1200741
742 /*for (Map.Entry<Prefix, PushedFlowMod> entry : pushedFlows.entries()) {
743 log.debug("Pushed flow: {} => {}", entry.getKey(), entry.getValue());
744 }*/
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200745
746 Collection<PushedFlowMod> pushedFlowMods
Jonathan Hart2f740782013-08-04 00:49:21 +1200747 = pushedFlows.removeAll(prefix);
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200748
749 for (PushedFlowMod pfm : pushedFlowMods) {
750 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
751 new Object[] {HexString.toHexString(pfm.getDpid()),
752 pfm.getFlowMod().getMatch().getNetworkDestination() +
753 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
754 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
755 .getDataLayerAddress())});
756
757 OFFlowMod fm = pfm.getFlowMod();
758
759 fm.setCommand(OFFlowMod.OFPFC_DELETE)
Jonathan Hart2f740782013-08-04 00:49:21 +1200760 .setOutPort(OFPort.OFPP_NONE)
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200761 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
762
763 fm.getActions().clear();
764
765 IOFSwitch sw = floodlightProvider.getSwitches().get(pfm.getDpid());
766 if (sw == null) {
767 log.warn("Switch not found when pushing delete flow mod");
768 continue;
769 }
770
771 try {
772 sw.write(fm, null);
773 sw.flush();
774 } catch (IOException e) {
775 log.error("Failure writing flow mod", e);
776 }
777 }
778 }
779
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700780 /*
781 * On startup we need to calculate a full mesh of paths between all gateway
782 * switches
783 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200784 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700785 //For each border router, calculate and install a path from every other
786 //border switch to said border router. However, don't install the entry
787 //in to the first hop switch, as we need to install an entry to rewrite
788 //for each prefix received. This will be done later when prefixes have
789 //actually been received.
790
Jonathan Hartc824ad02013-07-03 15:58:45 +1200791 for (BgpPeer peer : bgpPeers.values()) {
792 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200793
794 //See if we know the MAC address of the peer. If not we can't
795 //do anything until we learn it
796 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
797 if (mac == null) {
798 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
799 //Put in the pending paths list first
800 pathsWaitingOnArp.put(peer.getIpAddress(),
801 new PathUpdate(peerInterface, peer.getIpAddress()));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700802
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200803 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
804 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700805 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200806
807 //If we know the MAC, lets go ahead and push the paths to this peer
808 calculateAndPushPath(peerInterface, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700809 }
810 }
811
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200812 private void calculateAndPushPath(Interface dstInterface, MACAddress dstMacAddress) {
813 for (Interface srcInterface : interfaces.values()) {
814 if (dstInterface.equals(srcInterface.getName())){
815 continue;
816 }
817
818 DataPath shortestPath = topoRouteService.getShortestPath(
819 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
820
821 if (shortestPath == null){
822 log.debug("Shortest path between {} and {} not found",
823 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
824 return; // just quit here?
825 }
826
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200827 installPath(shortestPath.flowEntries(), dstMacAddress);
828 }
829 }
830
831 private void installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700832 //Set up the flow mod
833 OFFlowMod fm =
834 (OFFlowMod) floodlightProvider.getOFMessageFactory()
835 .getMessage(OFType.FLOW_MOD);
836
837 OFActionOutput action = new OFActionOutput();
838 action.setMaxLength((short)0xffff);
839 List<OFAction> actions = new ArrayList<OFAction>();
840 actions.add(action);
841
842 fm.setIdleTimeout((short)0)
843 .setHardTimeout((short)0)
844 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
845 .setCookie(L2_FWD_COOKIE)
846 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700847 .setActions(actions)
848 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
849
850 //Don't push the first flow entry. We need to push entries in the
851 //first switch based on IP prefix which we don't know yet.
852 for (int i = 1; i < flowEntries.size(); i++){
853 FlowEntry flowEntry = flowEntries.get(i);
854
855 OFMatch match = new OFMatch();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200856 //TODO Again using MAC address from configuration
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200857 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700858 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
859 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
860
861 fm.setMatch(match);
862
863 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
864
865 if (sw == null){
866 log.warn("Switch not found when pushing flow mod");
867 continue;
868 }
869
870 List<OFMessage> msglist = new ArrayList<OFMessage>();
871 msglist.add(fm);
872 try {
873 sw.write(msglist, null);
874 sw.flush();
875 } catch (IOException e) {
876 log.error("Failure writing flow mod", e);
877 }
878
879 try {
880 fm = fm.clone();
881 } catch (CloneNotSupportedException e1) {
882 log.error("Failure cloning flow mod", e1);
883 }
884 }
885 }
886
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200887 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200888 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200889 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
890
891 DataPath path = topoRouteService.getShortestPath(
892 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
893
894 if (path == null){
895 log.debug("Unable to compute path for BGP traffic for {}",
896 bgpPeer.getIpAddress());
897 continue;
898 }
899
900 //Set up the flow mod
901 OFFlowMod fm =
902 (OFFlowMod) floodlightProvider.getOFMessageFactory()
903 .getMessage(OFType.FLOW_MOD);
904
905 OFActionOutput action = new OFActionOutput();
906 action.setMaxLength((short)0xffff);
907 List<OFAction> actions = new ArrayList<OFAction>();
908 actions.add(action);
909
910 fm.setIdleTimeout((short)0)
911 .setHardTimeout((short)0)
912 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
913 .setCookie(BGP_COOKIE)
914 .setCommand(OFFlowMod.OFPFC_ADD)
915 .setPriority(SDNIP_PRIORITY)
916 .setActions(actions)
917 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
918
919 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
920 OFMatch forwardMatchSrc = new OFMatch();
921
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200922 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
923 + "/32";
924 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
925 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200926
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200927 //Common match fields
928 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
929 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
930 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
931 forwardMatchSrc.setTransportDestination(BGP_PORT);
932 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
933 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
934
935
936 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
937
938 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
939 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
940
941 OFMatch forwardMatchDst = forwardMatchSrc.clone();
942
943 forwardMatchSrc.setTransportSource(BGP_PORT);
944 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
945 forwardMatchDst.setTransportDestination(BGP_PORT);
946 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
947
948 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
949 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
950
951 OFMatch reverseMatchDst = reverseMatchSrc.clone();
952
953 reverseMatchSrc.setTransportSource(BGP_PORT);
954 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
955 reverseMatchDst.setTransportDestination(BGP_PORT);
956 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
957
958 fm.setMatch(forwardMatchSrc);
959
Jonathan Hart38c84932013-08-10 17:49:27 +1200960 OFMatch forwardIcmpMatch = new OFMatch();
961 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
962 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
963 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
964 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
965
966 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
967 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
968 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
969
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200970 for (FlowEntry flowEntry : path.flowEntries()){
971 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
972 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200973 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200974 try {
975 forwardFlowModSrc = fm.clone();
976 forwardFlowModDst = fm.clone();
977 reverseFlowModSrc = fm.clone();
978 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200979 forwardIcmp = fm.clone();
980 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200981 } catch (CloneNotSupportedException e) {
982 log.warn("Clone failed", e);
983 continue;
984 }
985
986 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
987 forwardFlowModSrc.setMatch(forwardMatchSrc);
988 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
989 .setPort(flowEntry.outPort().value());
990
991 forwardMatchDst.setInputPort(flowEntry.inPort().value());
992 forwardFlowModDst.setMatch(forwardMatchDst);
993 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
994 .setPort(flowEntry.outPort().value());
995
996 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
997 reverseFlowModSrc.setMatch(reverseMatchSrc);
998 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
999 .setPort(flowEntry.inPort().value());
1000
1001 reverseMatchDst.setInputPort(flowEntry.outPort().value());
1002 reverseFlowModDst.setMatch(reverseMatchDst);
1003 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
1004 .setPort(flowEntry.inPort().value());
1005
Jonathan Hart38c84932013-08-10 17:49:27 +12001006 ((OFActionOutput)forwardIcmp.getActions().get(0))
1007 .setPort(flowEntry.outPort().value());
1008 forwardIcmp.setMatch(forwardIcmpMatch);
1009
1010 ((OFActionOutput)reverseIcmp.getActions().get(0))
1011 .setPort(flowEntry.inPort().value());
1012 reverseIcmp.setMatch(reverseIcmpMatch);
1013
1014
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001015 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
1016
Jonathan Hart38c84932013-08-10 17:49:27 +12001017 if (sw == null) {
1018 log.warn("Switch not found when pushing BGP paths");
1019 return;
1020 }
1021
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001022 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
1023 msgList.add(forwardFlowModSrc);
1024 msgList.add(forwardFlowModDst);
1025 msgList.add(reverseFlowModSrc);
1026 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +12001027 msgList.add(forwardIcmp);
1028 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001029
1030 try {
1031 sw.write(msgList, null);
1032 sw.flush();
1033 } catch (IOException e) {
1034 log.error("Failure writing flow mod", e);
1035 }
1036 }
1037 }
1038 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001039
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001040 @Override
1041 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
1042 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
1043 MACAddress.valueOf(macAddress).toString());
1044
1045 Set<PathUpdate> pathsToPush = pathsWaitingOnArp.removeAll(ipAddress);
1046
1047 for (PathUpdate update : pathsToPush) {
1048 log.debug("Pushing path to {} at {} on {}", new Object[] {
1049 update.getDstIpAddress().getHostAddress(),
1050 MACAddress.valueOf(macAddress),
1051 update.getDstInterface().getSwitchPort()});
1052 calculateAndPushPath(update.getDstInterface(),
1053 MACAddress.valueOf(macAddress));
1054 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001055
1056 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
1057
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001058 /*
1059 * We synchronize on this to prevent changes to the ptree while we're pushing
1060 * flows to the switches. If the ptree changes, the ptree and switches
1061 * could get out of sync.
1062 */
1063 synchronized (this) {
1064 for (RibUpdate update : prefixesToPush) {
1065 //These will always be adds
1066
1067 //addPrefixFlows(update.getPrefix(), update.getRibEntry());
1068 //processRibAdd(update);
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001069 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001070 if (rib != null && rib.equals(update.getRibEntry())) {
1071 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001072 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001073 //We only push prefix flows if the prefix is still in the ptree
1074 //and the next hop is the same as our update. The prefix could
1075 //have been removed while we were waiting for the ARP, or the
1076 //next hop could have changed.
1077 addPrefixFlows(update.getPrefix(), rib);
1078 } else {
1079 log.debug("Received ARP response, but {},{} is no longer in ptree",
1080 update.getPrefix(), update.getRibEntry());
1081 }
1082 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001083 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001084 }
1085
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001086 private void beginRouting(){
1087 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001088 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001089 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001090
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001091 //Traverse ptree and create flows for all routes
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001092 /*
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001093 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
1094 if (node.rib != null){
1095 prefixAdded(node);
1096 }
1097 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001098 */
1099
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001100 /*
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001101 synchronized (ptree) {
1102 Iterator<IPatriciaTrie.Entry> it = ptree.iterator();
1103 while (it.hasNext()) {
1104 IPatriciaTrie.Entry entry = it.next();
1105 addPrefixFlows(entry.getPrefix(), entry.getRib());
1106 }
1107 }
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001108 */
1109
1110 bgpUpdatesExecutor.execute(new Runnable() {
1111 @Override
1112 public void run() {
1113 doUpdatesThread();
1114 }
1115 });
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001116
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001117 }
1118
1119 private void checkSwitchesConnected(){
1120 for (String dpid : switches){
1121 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1122 log.debug("Not all switches are here yet");
1123 return;
1124 }
1125 }
1126 switchesConnected = true;
1127 }
1128
Jonathan Hartc824ad02013-07-03 15:58:45 +12001129 //Actually we only need to go half way round to verify full mesh connectivity
1130 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001131 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001132 for (Interface dstInterface : interfaces.values()) {
1133 for (Interface srcInterface : interfaces.values()) {
1134 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001135 continue;
1136 }
1137
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001138 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001139 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001140
1141 if (shortestPath == null){
1142 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001143 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001144 return;
1145 }
1146 }
1147 }
1148 topologyReady = true;
1149 }
1150
1151 private void checkStatus(){
1152 log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
1153
1154 if (!switchesConnected){
1155 checkSwitchesConnected();
1156 }
1157 boolean oldTopologyReadyStatus = topologyReady;
1158 if (switchesConnected && !topologyReady){
1159 checkTopologyReady();
1160 }
1161 if (!oldTopologyReadyStatus && topologyReady){
1162 beginRouting();
1163 }
1164 }
1165
pingping-lina2cbfad2013-03-07 08:39:21 +08001166 @Override
1167 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +08001168 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001169 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -07001170 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +08001171
Jonathan Hartc7ca35d2013-06-25 20:54:25 +12001172 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
1173
Jonathan Hart61ba9372013-05-19 20:10:29 -07001174 //Retrieve the RIB from BGPd during startup
1175 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +08001176 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001177
1178 private void doUpdatesThread() {
1179 boolean interrupted = false;
1180 try {
1181 while (true) {
1182 try {
1183 RibUpdate update = ribUpdates.take();
1184 switch (update.getOperation()){
1185 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001186 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001187 break;
1188 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001189 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001190 break;
1191 }
1192 } catch (InterruptedException e) {
Jonathan Hart9ea31212013-08-12 21:40:34 +12001193 log.debug("interrupted", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001194 interrupted = true;
1195 }
1196 }
1197 } finally {
1198 if (interrupted) {
1199 Thread.currentThread().interrupt();
1200 }
1201 }
1202 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001203
1204 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001205 public void topologyChanged() {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001206 boolean refreshNeeded = false;
1207 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1208 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1209 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001210 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001211 refreshNeeded = true;
1212 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001213
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001214 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001215
Jonathan Hart98957bf2013-07-01 14:49:24 +12001216 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1217 synchronized (linkUpdates) {
1218 linkUpdates.add(ldu);
1219 }
1220 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001221 }
1222
1223 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001224 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001225 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001226 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001227
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001228 //TODO determine whether we need to listen for switch joins
1229 @Override
1230 public void addedSwitch(IOFSwitch sw) {
1231 //checkStatus();
1232 }
1233
1234 @Override
1235 public void removedSwitch(IOFSwitch sw) {
1236 // TODO Auto-generated method stub
1237 }
1238
1239 @Override
1240 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001241
1242 @Override
1243 public String getName() {
1244 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +08001245 }
1246}