blob: acdf185e98cd826f4922f9b1549eaab3260e6ba8 [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 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 Hart98957bf2013-07-01 14:49:24 +120035import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070036import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120037import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070038import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
39import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120040import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070041import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070042import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120043import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070044import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070045import net.onrc.onos.ofcontroller.util.Port;
46import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080047import net.sf.json.JSONArray;
48import net.sf.json.JSONObject;
49import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080050
Jonathan Hartd1f23252013-06-13 15:17:05 +120051import org.codehaus.jackson.JsonParseException;
52import org.codehaus.jackson.map.JsonMappingException;
53import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070054import org.openflow.protocol.OFFlowMod;
55import org.openflow.protocol.OFMatch;
56import org.openflow.protocol.OFMessage;
57import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120058import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070059import org.openflow.protocol.OFType;
60import org.openflow.protocol.action.OFAction;
61import org.openflow.protocol.action.OFActionDataLayerDestination;
62import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120063import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080064import org.slf4j.Logger;
65import org.slf4j.LoggerFactory;
66
Jonathan Hart8b9349e2013-07-26 15:55:28 +120067import com.google.common.util.concurrent.ThreadFactoryBuilder;
68
Jonathan Hart1236a9b2013-06-18 22:10:05 +120069public class BgpRoute implements IFloodlightModule, IBgpRouteService,
70 ITopologyListener, IOFSwitchListener {
pingping-lina2cbfad2013-03-07 08:39:21 +080071
72 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
73
74 protected IFloodlightProviderService floodlightProvider;
75 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070076 protected ITopoRouteService topoRouteService;
77 protected IDeviceService devices;
78 protected IRestApiService restApi;
79
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120080 protected ProxyArpManager proxyArp;
81
pingping-lina2cbfad2013-03-07 08:39:21 +080082 protected static Ptree ptree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120083 protected BlockingQueue<RibUpdate> ribUpdates;
84
Jonathan Hart61ba9372013-05-19 20:10:29 -070085 protected String bgpdRestIp;
86 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120087 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070088
89 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
90 //the controller/OS should hand out cookie IDs to prevent conflicts.
91 protected final long APP_COOKIE = 0xa0000000000000L;
92 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
93 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
94 //Cookie for flows in ingress switches that rewrite the MAC address
95 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120096 //Cookie for flows that setup BGP paths
97 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +120098 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
99 //need to be higher priority than this otherwise the rewrite may not get done
100 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700101
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200102 protected final short BGP_PORT = 179;
103
Jonathan Hart98957bf2013-07-01 14:49:24 +1200104 protected final int TOPO_DETECTION_WAIT = 2; //seconds
105
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200106 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200107 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200108 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200109 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200110 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200111
112 //True when all switches have connected
113 protected volatile boolean switchesConnected = false;
114 //True when we have a full mesh of shortest paths between gateways
115 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200116
Jonathan Hart98957bf2013-07-01 14:49:24 +1200117 protected ArrayList<LDUpdate> linkUpdates;
118 protected SingletonTask topologyChangeDetectorTask;
119
Jonathan Hart98957bf2013-07-01 14:49:24 +1200120 protected class TopologyChangeDetector implements Runnable {
121 @Override
122 public void run() {
123 log.debug("Running topology change detection task");
124 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200125 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200126 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
127
128 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200129 //for (Link l : activeLinks){
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200130 //log.debug("active link: {}", l);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200131 //}
Jonathan Hart98957bf2013-07-01 14:49:24 +1200132
133 Iterator<LDUpdate> it = linkUpdates.iterator();
134 while (it.hasNext()){
135 LDUpdate ldu = it.next();
136 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
137 ldu.getDst(), ldu.getDstPort());
138
139 if (activeLinks.contains(l)){
140 log.debug("Not found: {}", l);
141 it.remove();
142 }
143 }
144 }
145
146 if (linkUpdates.isEmpty()){
147 //All updates have been seen in network map.
148 //We can check if topology is ready
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200149 log.debug("No known changes outstanding. Checking topology now");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200150 checkStatus();
151 }
152 else {
153 //We know of some link updates that haven't propagated to the database yet
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200154 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200155 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
156 }
157 }
158 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700159
Jonathan Hartd1f23252013-06-13 15:17:05 +1200160 private void readGatewaysConfiguration(String gatewaysFilename){
161 File gatewaysFile = new File(gatewaysFilename);
162 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700163
Jonathan Hartd1f23252013-06-13 15:17:05 +1200164 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200165 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
166
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200167 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200168 interfaces = new HashMap<String, Interface>();
169 for (Interface intf : config.getInterfaces()){
170 interfaces.put(intf.getName(), intf);
171 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200172 bgpPeers = new HashMap<InetAddress, BgpPeer>();
173 for (BgpPeer peer : config.getPeers()){
174 bgpPeers.put(peer.getIpAddress(), peer);
175 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200176
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200177 bgpdAttachmentPoint = new SwitchPort(
178 new Dpid(config.getBgpdAttachmentDpid()),
179 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200180
Jonathan Hartd1f23252013-06-13 15:17:05 +1200181 } catch (JsonParseException e) {
182 log.error("Error in JSON file", e);
183 System.exit(1);
184 } catch (JsonMappingException e) {
185 log.error("Error in JSON file", e);
186 System.exit(1);
187 } catch (IOException e) {
188 log.error("Error reading JSON file", e);
189 System.exit(1);
190 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700191 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800192
193 @Override
194 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700195 Collection<Class<? extends IFloodlightService>> l
196 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800197 l.add(IBgpRouteService.class);
198 return l;
199 }
200
201 @Override
202 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700203 Map<Class<? extends IFloodlightService>, IFloodlightService> m
204 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800205 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800206 return m;
207 }
208
pingping-lina2cbfad2013-03-07 08:39:21 +0800209 @Override
210 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700211 Collection<Class<? extends IFloodlightService>> l
212 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800213 l.add(IFloodlightProviderService.class);
214 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700215 l.add(IDeviceService.class);
216 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800217 return l;
218 }
219
220 @Override
221 public void init(FloodlightModuleContext context)
222 throws FloodlightModuleException {
223
224 ptree = new Ptree(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200225
226 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200227
pingping-lina2cbfad2013-03-07 08:39:21 +0800228 // Register floodlight provider and REST handler.
229 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800230 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700231 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200232 restApi = context.getServiceImpl(IRestApiService.class);
233
234 //TODO We'll initialise this here for now, but it should really be done as
235 //part of the controller core
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200236 proxyArp = new ProxyArpManager(floodlightProvider, topology, devices);
pingping-lina2cbfad2013-03-07 08:39:21 +0800237
Jonathan Hart98957bf2013-07-01 14:49:24 +1200238 linkUpdates = new ArrayList<LDUpdate>();
239 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
240 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700241
242 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200243
Jonathan Hart61ba9372013-05-19 20:10:29 -0700244 //Read in config values
245 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
246 if (bgpdRestIp == null){
247 log.error("BgpdRestIp property not found in config file");
248 System.exit(1);
249 }
250 else {
251 log.info("BgpdRestIp set to {}", bgpdRestIp);
252 }
253
254 routerId = context.getConfigParams(this).get("RouterId");
255 if (routerId == null){
256 log.error("RouterId property not found in config file");
257 System.exit(1);
258 }
259 else {
260 log.info("RouterId set to {}", routerId);
261 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200262
Jonathan Hart9575cb62013-07-05 13:43:49 +1200263 String configFilenameParameter = context.getConfigParams(this).get("configfile");
264 if (configFilenameParameter != null){
265 configFilename = configFilenameParameter;
266 }
267 log.debug("Config file set to {}", configFilename);
268
269 readGatewaysConfiguration(configFilename);
pingping-lina2cbfad2013-03-07 08:39:21 +0800270 // Test.
271 //test();
272 }
273
274 public Ptree getPtree() {
275 return ptree;
276 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700277
278 public void clearPtree() {
279 //ptree = null;
280 ptree = new Ptree(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800281 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700282
pingping-line2a09ca2013-03-23 09:33:58 +0800283 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700284 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800285 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700286
pingping-line2a09ca2013-03-23 09:33:58 +0800287 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700288 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800289 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800290
291 // Return nexthop address as byte array.
292 public Rib lookupRib(byte[] dest) {
293 if (ptree == null) {
294 log.debug("lookupRib: ptree null");
295 return null;
296 }
297
298 PtreeNode node = ptree.match(dest, 32);
299 if (node == null) {
300 log.debug("lookupRib: ptree node null");
301 return null;
302 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700303
pingping-lina2cbfad2013-03-07 08:39:21 +0800304 if (node.rib == null) {
305 log.debug("lookupRib: ptree rib null");
306 return null;
307 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700308
pingping-lina2cbfad2013-03-07 08:39:21 +0800309 ptree.delReference(node);
310
311 return node.rib;
312 }
313
Jonathan Hart61ba9372013-05-19 20:10:29 -0700314 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800315 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700316 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800317 System.out.println("Here it is");
318 Prefix p = new Prefix("128.0.0.0", 8);
319 Prefix q = new Prefix("8.0.0.0", 8);
320 Prefix r = new Prefix("10.0.0.0", 24);
321 Prefix a = new Prefix("10.0.0.1", 32);
322
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200323 ptree.acquire(p.getAddress(), p.getPrefixLength());
324 ptree.acquire(q.getAddress(), q.getPrefixLength());
325 ptree.acquire(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800326
327 System.out.println("Traverse start");
328 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
329 Prefix p_result = new Prefix(node.key, node.keyBits);
330 }
331
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200332 PtreeNode n = ptree.match(a.getAddress(), a.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800333 if (n != null) {
334 System.out.println("Matched prefix for 10.0.0.1:");
335 Prefix x = new Prefix(n.key, n.keyBits);
336 ptree.delReference(n);
337 }
338
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200339 n = ptree.lookup(p.getAddress(), p.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800340 if (n != null) {
341 ptree.delReference(n);
342 ptree.delReference(n);
343 }
344 System.out.println("Traverse start");
345 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
346 Prefix p_result = new Prefix(node.key, node.keyBits);
347 }
348
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200349 n = ptree.lookup(q.getAddress(), q.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800350 if (n != null) {
351 ptree.delReference(n);
352 ptree.delReference(n);
353 }
354 System.out.println("Traverse start");
355 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
356 Prefix p_result = new Prefix(node.key, node.keyBits);
357 }
358
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200359 n = ptree.lookup(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800360 if (n != null) {
361 ptree.delReference(n);
362 ptree.delReference(n);
363 }
364 System.out.println("Traverse start");
365 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
366 Prefix p_result = new Prefix(node.key, node.keyBits);
367 }
368
369 }
370
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200371 private String getPrefixFromPtree(PtreeNode node){
372 InetAddress address = null;
373 try {
374 address = InetAddress.getByAddress(node.key);
375 } catch (UnknownHostException e1) {
376 //Should never happen is the reverse conversion has already been done
377 log.error("Malformed IP address");
378 return "";
379 }
380 return address.toString() + "/" + node.rib.masklen;
381 }
382
Jonathan Hart61ba9372013-05-19 20:10:29 -0700383 private void retrieveRib(){
384 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
385 String response = RestClient.get(url);
386
387 if (response.equals("")){
388 return;
389 }
390
391 response = response.replaceAll("\"", "'");
392 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
393 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
394 String router_id = jsonObj.getString("router-id");
395
396 int size = rib_json_array.size();
397
398 log.info("Retrived RIB of {} entries from BGPd", size);
399
400 for (int j = 0; j < size; j++) {
401 JSONObject second_json_object = rib_json_array.getJSONObject(j);
402 String prefix = second_json_object.getString("prefix");
403 String nexthop = second_json_object.getString("nexthop");
404
405 //insert each rib entry into the local rib;
406 String[] substring = prefix.split("/");
407 String prefix1 = substring[0];
408 String mask1 = substring[1];
409
410 Prefix p;
411 try {
412 p = new Prefix(prefix1, Integer.valueOf(mask1));
413 } catch (NumberFormatException e) {
414 log.warn("Wrong mask format in RIB JSON: {}", mask1);
415 continue;
416 } catch (UnknownHostException e1) {
417 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
418 continue;
419 }
420
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200421 PtreeNode node = ptree.acquire(p.getAddress(), p.getPrefixLength());
422 Rib rib = new Rib(router_id, nexthop, p.getPrefixLength());
Jonathan Hart61ba9372013-05-19 20:10:29 -0700423
424 if (node.rib != null) {
425 node.rib = null;
426 ptree.delReference(node);
427 }
428
429 node.rib = rib;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700430
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200431 prefixAdded(node);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700432 }
433 }
434
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200435 @Override
436 public void newRibUpdate(RibUpdate update) {
437 ribUpdates.add(update);
438 }
439
440 //TODO temporary
441 public void wrapPrefixAdded(RibUpdate update) {
442 Prefix prefix = update.getPrefix();
443
444 PtreeNode node = ptree.acquire(prefix.getAddress(), prefix.getPrefixLength());
445
446 if (node.rib != null) {
447 node.rib = null;
448 ptree.delReference(node);
449 }
450 node.rib = update.getRibEntry();
451
452 prefixAdded(node);
453 }
454
455 //TODO temporary
456 public void wrapPrefixDeleted(RibUpdate update) {
457 Prefix prefix = update.getPrefix();
458
459 PtreeNode node = ptree.lookup(prefix.getAddress(), prefix.getPrefixLength());
460
461 /*
462 * Remove the flows from the switches before the rib is lost
463 * Theory: we could get a delete for a prefix not in the Ptree.
464 * This would result in a null node being returned. We could get a delete for
465 * a node that's not actually there, but is a aggregate node. This would result
466 * in a non-null node with a null rib. Only a non-null node with a non-null
467 * rib is an actual prefix in the Ptree.
468 */
469 if (node != null && node.rib != null){
470 prefixDeleted(node);
471 }
472
473 if (node != null && node.rib != null) {
474 if (update.getRibEntry().equals(node.rib)) {
475 node.rib = null;
476 ptree.delReference(node);
477 }
478 }
479 }
480
481 @Override
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200482 public void prefixAdded(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200483 if (!topologyReady){
484 return;
485 }
486
487 String prefix = getPrefixFromPtree(node);
488
Jonathan Hartc824ad02013-07-03 15:58:45 +1200489 log.debug("New prefix {} added, next hop {}, routerId {}",
490 new Object[] {prefix, node.rib.nextHop.toString(),
491 node.rib.routerId.getHostAddress()});
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200492
Jonathan Hartc824ad02013-07-03 15:58:45 +1200493 //TODO this is wrong, we shouldn't be dealing with BGP peers here.
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200494 //We need to figure out where the device is attached and what its
Jonathan Hartc824ad02013-07-03 15:58:45 +1200495 //mac address is by learning.
496 //The next hop is not necessarily the peer, and the peer's attachment
497 //point is not necessarily the next hop's attachment point.
498 BgpPeer peer = bgpPeers.get(node.rib.nextHop);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700499
Jonathan Hartc824ad02013-07-03 15:58:45 +1200500 if (peer == null){
501 //TODO local router isn't in peers list so this will get thrown
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200502 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
Jonathan Hartc824ad02013-07-03 15:58:45 +1200503
504 //The other scenario is this is a route server route. In that
505 //case the next hop is not in our configuration
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200506 log.error("Couldn't find next hop router in router {} in config"
507 , node.rib.nextHop.toString());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700508 return; //just quit out here? This is probably a configuration error
509 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200510
511 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200512
Jonathan Hartc824ad02013-07-03 15:58:45 +1200513 //Add a flow to rewrite mac for this prefix to all border switches
514 for (Interface srcInterface : interfaces.values()) {
515 if (srcInterface == peerInterface) {
516 //Don't push a flow for the switch where this peer is attached
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700517 continue;
518 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200519
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700520 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200521 srcInterface.getSwitchPort(),
522 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700523
524 if (shortestPath == null){
525 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200526 srcInterface.getSwitchPort(),
527 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700528 return; // just quit here?
529 }
530
531 //TODO check the shortest path against the cached version we
532 //calculated before. If they don't match up that's a problem
533
534 //Set up the flow mod
535 OFFlowMod fm =
536 (OFFlowMod) floodlightProvider.getOFMessageFactory()
537 .getMessage(OFType.FLOW_MOD);
538
539 fm.setIdleTimeout((short)0)
540 .setHardTimeout((short)0)
541 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
542 .setCookie(MAC_RW_COOKIE)
543 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200544 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700545 .setLengthU(OFFlowMod.MINIMUM_LENGTH
546 + OFActionDataLayerDestination.MINIMUM_LENGTH
547 + OFActionOutput.MINIMUM_LENGTH);
548
549 OFMatch match = new OFMatch();
550 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200551 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700552
Jonathan Hartc824ad02013-07-03 15:58:45 +1200553 //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
554 //match.setDataLayerSource(peer.getMacAddress().toBytes());
555 //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200556
557 InetAddress address = null;
558 try {
559 address = InetAddress.getByAddress(node.key);
560 } catch (UnknownHostException e1) {
561 //Should never happen is the reverse conversion has already been done
562 log.error("Malformed IP address");
563 return;
564 }
565
566 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
567 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700568
569 //Set up MAC rewrite action
570 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200571 //TODO use ARP module rather than configured mac addresses
572 //TODO the peer's mac address is not necessarily the next hop's...
573 macRewriteAction.setDataLayerAddress(peer.getMacAddress().toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700574
575 //Set up output action
576 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200577 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700578
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200579 Port outputPort = shortestPath.flowEntries().get(0).outPort();
580 outputAction.setPort(outputPort.value());
581
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700582 List<OFAction> actions = new ArrayList<OFAction>();
583 actions.add(macRewriteAction);
584 actions.add(outputAction);
585 fm.setActions(actions);
586
587 //Write to switch
588 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200589 .get(srcInterface.getDpid());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700590
591 if (sw == null){
592 log.warn("Switch not found when pushing flow mod");
593 continue;
594 }
595
596 List<OFMessage> msglist = new ArrayList<OFMessage>();
597 msglist.add(fm);
598 try {
599 sw.write(msglist, null);
600 sw.flush();
601 } catch (IOException e) {
602 log.error("Failure writing flow mod", e);
603 }
604 }
605 }
606
Jonathan Hartc824ad02013-07-03 15:58:45 +1200607 //TODO this is largely untested
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200608 @Override
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200609 public void prefixDeleted(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200610 if (!topologyReady) {
611 return;
612 }
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200613
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200614 String prefix = getPrefixFromPtree(node);
615
616 log.debug("Prefix {} deleted, next hop {}",
617 prefix, node.rib.nextHop.toString());
618
619 //Remove MAC rewriting flows from other border switches
Jonathan Hartc824ad02013-07-03 15:58:45 +1200620 BgpPeer peer = bgpPeers.get(node.rib.nextHop);
621 if (peer == null){
622 //either a router server route or local route. Can't handle right now
623 return;
624 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200625
Jonathan Hartc824ad02013-07-03 15:58:45 +1200626 Interface peerInterface = interfaces.get(peer.getInterfaceName());
627
628 for (Interface srcInterface : interfaces.values()) {
629 if (srcInterface == peerInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200630 continue;
631 }
632
633 //Set up the flow mod
634 OFFlowMod fm =
635 (OFFlowMod) floodlightProvider.getOFMessageFactory()
636 .getMessage(OFType.FLOW_MOD);
637
638 fm.setIdleTimeout((short)0)
639 .setHardTimeout((short)0)
640 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
641 .setCookie(MAC_RW_COOKIE)
642 .setCommand(OFFlowMod.OFPFC_DELETE)
Jonathan Hart9575cb62013-07-05 13:43:49 +1200643 .setOutPort(OFPort.OFPP_NONE)
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200644 .setPriority(SDNIP_PRIORITY)
645 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
646 //+ OFActionDataLayerDestination.MINIMUM_LENGTH
647 //+ OFActionOutput.MINIMUM_LENGTH);
648
649 OFMatch match = new OFMatch();
650 match.setDataLayerType(Ethernet.TYPE_IPv4);
651 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
652
Jonathan Hartc824ad02013-07-03 15:58:45 +1200653 //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
654 //match.setDataLayerSource(peer.getMacAddress().toBytes());
655 //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200656
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200657 InetAddress address = null;
658 try {
659 address = InetAddress.getByAddress(node.key);
660 } catch (UnknownHostException e1) {
661 //Should never happen is the reverse conversion has already been done
662 log.error("Malformed IP address");
663 return;
664 }
665
666 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
667 fm.setMatch(match);
668
669 //Write to switch
670 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200671 .get(srcInterface.getDpid());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200672
673 if (sw == null){
674 log.warn("Switch not found when pushing flow mod");
675 continue;
676 }
677
678 List<OFMessage> msglist = new ArrayList<OFMessage>();
679 msglist.add(fm);
680 try {
681 sw.write(msglist, null);
682 sw.flush();
683 } catch (IOException e) {
684 log.error("Failure writing flow mod", e);
685 }
686 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700687 }
688
689 /*
690 * On startup we need to calculate a full mesh of paths between all gateway
691 * switches
692 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200693 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700694 //For each border router, calculate and install a path from every other
695 //border switch to said border router. However, don't install the entry
696 //in to the first hop switch, as we need to install an entry to rewrite
697 //for each prefix received. This will be done later when prefixes have
698 //actually been received.
699
Jonathan Hartc824ad02013-07-03 15:58:45 +1200700 for (BgpPeer peer : bgpPeers.values()) {
701 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart9575cb62013-07-05 13:43:49 +1200702 //for (Map.Entry<String, Interface> intfEntry : interfaces.entrySet()) {
703 for (Interface srcInterface : interfaces.values()) {
704 //Interface srcInterface = intfEntry.getValue();
705 //if (peer.getInterfaceName().equals(intfEntry.getKey())){
706 if (peer.getInterfaceName().equals(srcInterface.getName())){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700707 continue;
708 }
709
710 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200711 srcInterface.getSwitchPort(), peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700712
713 if (shortestPath == null){
714 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200715 srcInterface.getSwitchPort(), peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700716 return; // just quit here?
717 }
718
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700719 //install flows
Jonathan Hartc824ad02013-07-03 15:58:45 +1200720 installPath(shortestPath.flowEntries(), peer);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700721 }
722 }
723 }
724
Jonathan Hartc824ad02013-07-03 15:58:45 +1200725 private void installPath(List<FlowEntry> flowEntries, BgpPeer peer){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700726 //Set up the flow mod
727 OFFlowMod fm =
728 (OFFlowMod) floodlightProvider.getOFMessageFactory()
729 .getMessage(OFType.FLOW_MOD);
730
731 OFActionOutput action = new OFActionOutput();
732 action.setMaxLength((short)0xffff);
733 List<OFAction> actions = new ArrayList<OFAction>();
734 actions.add(action);
735
736 fm.setIdleTimeout((short)0)
737 .setHardTimeout((short)0)
738 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
739 .setCookie(L2_FWD_COOKIE)
740 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700741 .setActions(actions)
742 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
743
744 //Don't push the first flow entry. We need to push entries in the
745 //first switch based on IP prefix which we don't know yet.
746 for (int i = 1; i < flowEntries.size(); i++){
747 FlowEntry flowEntry = flowEntries.get(i);
748
749 OFMatch match = new OFMatch();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200750 //TODO Again using MAC address from configuration
751 match.setDataLayerDestination(peer.getMacAddress().toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700752 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
753 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
754
755 fm.setMatch(match);
756
757 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
758
759 if (sw == null){
760 log.warn("Switch not found when pushing flow mod");
761 continue;
762 }
763
764 List<OFMessage> msglist = new ArrayList<OFMessage>();
765 msglist.add(fm);
766 try {
767 sw.write(msglist, null);
768 sw.flush();
769 } catch (IOException e) {
770 log.error("Failure writing flow mod", e);
771 }
772
773 try {
774 fm = fm.clone();
775 } catch (CloneNotSupportedException e1) {
776 log.error("Failure cloning flow mod", e1);
777 }
778 }
779 }
780
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200781 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200782 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200783 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
784
785 DataPath path = topoRouteService.getShortestPath(
786 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
787
788 if (path == null){
789 log.debug("Unable to compute path for BGP traffic for {}",
790 bgpPeer.getIpAddress());
791 continue;
792 }
793
794 //Set up the flow mod
795 OFFlowMod fm =
796 (OFFlowMod) floodlightProvider.getOFMessageFactory()
797 .getMessage(OFType.FLOW_MOD);
798
799 OFActionOutput action = new OFActionOutput();
800 action.setMaxLength((short)0xffff);
801 List<OFAction> actions = new ArrayList<OFAction>();
802 actions.add(action);
803
804 fm.setIdleTimeout((short)0)
805 .setHardTimeout((short)0)
806 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
807 .setCookie(BGP_COOKIE)
808 .setCommand(OFFlowMod.OFPFC_ADD)
809 .setPriority(SDNIP_PRIORITY)
810 .setActions(actions)
811 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
812
813 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
814 OFMatch forwardMatchSrc = new OFMatch();
815
816
817 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
818 + "/32";
819 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
820 + "/32";
821
822 //Common match fields
823 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
824 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
825 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
826 forwardMatchSrc.setTransportDestination(BGP_PORT);
827 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
828 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
829
830
831 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
832
833 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
834 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
835
836 OFMatch forwardMatchDst = forwardMatchSrc.clone();
837
838 forwardMatchSrc.setTransportSource(BGP_PORT);
839 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
840 forwardMatchDst.setTransportDestination(BGP_PORT);
841 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
842
843 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
844 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
845
846 OFMatch reverseMatchDst = reverseMatchSrc.clone();
847
848 reverseMatchSrc.setTransportSource(BGP_PORT);
849 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
850 reverseMatchDst.setTransportDestination(BGP_PORT);
851 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
852
853 fm.setMatch(forwardMatchSrc);
854
855 for (FlowEntry flowEntry : path.flowEntries()){
856 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
857 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
858 try {
859 forwardFlowModSrc = fm.clone();
860 forwardFlowModDst = fm.clone();
861 reverseFlowModSrc = fm.clone();
862 reverseFlowModDst = fm.clone();
863 } catch (CloneNotSupportedException e) {
864 log.warn("Clone failed", e);
865 continue;
866 }
867
868 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
869 forwardFlowModSrc.setMatch(forwardMatchSrc);
870 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
871 .setPort(flowEntry.outPort().value());
872
873 forwardMatchDst.setInputPort(flowEntry.inPort().value());
874 forwardFlowModDst.setMatch(forwardMatchDst);
875 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
876 .setPort(flowEntry.outPort().value());
877
878 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
879 reverseFlowModSrc.setMatch(reverseMatchSrc);
880 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
881 .setPort(flowEntry.inPort().value());
882
883 reverseMatchDst.setInputPort(flowEntry.outPort().value());
884 reverseFlowModDst.setMatch(reverseMatchDst);
885 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
886 .setPort(flowEntry.inPort().value());
887
888 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
889
890 //Hopefully the switch is there
891 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
892 msgList.add(forwardFlowModSrc);
893 msgList.add(forwardFlowModDst);
894 msgList.add(reverseFlowModSrc);
895 msgList.add(reverseFlowModDst);
896
897 try {
898 sw.write(msgList, null);
899 sw.flush();
900 } catch (IOException e) {
901 log.error("Failure writing flow mod", e);
902 }
903 }
904 }
905 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200906
907 private void beginRouting(){
908 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200909 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200910 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200911
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200912 //Traverse ptree and create flows for all routes
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200913 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
914 if (node.rib != null){
915 prefixAdded(node);
916 }
917 }
918 }
919
920 private void checkSwitchesConnected(){
921 for (String dpid : switches){
922 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
923 log.debug("Not all switches are here yet");
924 return;
925 }
926 }
927 switchesConnected = true;
928 }
929
Jonathan Hartc824ad02013-07-03 15:58:45 +1200930 //Actually we only need to go half way round to verify full mesh connectivity
931 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200932 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200933 for (Interface dstInterface : interfaces.values()) {
934 for (Interface srcInterface : interfaces.values()) {
935 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200936 continue;
937 }
938
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200939 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200940 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200941
942 if (shortestPath == null){
943 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200944 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200945 return;
946 }
947 }
948 }
949 topologyReady = true;
950 }
951
952 private void checkStatus(){
953 log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
954
955 if (!switchesConnected){
956 checkSwitchesConnected();
957 }
958 boolean oldTopologyReadyStatus = topologyReady;
959 if (switchesConnected && !topologyReady){
960 checkTopologyReady();
961 }
962 if (!oldTopologyReadyStatus && topologyReady){
963 beginRouting();
964 }
965 }
966
pingping-lina2cbfad2013-03-07 08:39:21 +0800967 @Override
968 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +0800969 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200970 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700971 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +0800972
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200973 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
974
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200975 ExecutorService e = Executors.newSingleThreadExecutor(
976 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
977
978
979 e.execute(new Runnable() {
980 @Override
981 public void run() {
982 doUpdatesThread();
983 }
984 });
985
Jonathan Hart61ba9372013-05-19 20:10:29 -0700986 //Retrieve the RIB from BGPd during startup
987 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800988 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200989
990 private void doUpdatesThread() {
991 boolean interrupted = false;
992 try {
993 while (true) {
994 try {
995 RibUpdate update = ribUpdates.take();
996 switch (update.getOperation()){
997 case UPDATE:
998 wrapPrefixAdded(update);
999 break;
1000 case DELETE:
1001 wrapPrefixDeleted(update);
1002 break;
1003 }
1004 } catch (InterruptedException e) {
1005 interrupted = true;
1006 }
1007 }
1008 } finally {
1009 if (interrupted) {
1010 Thread.currentThread().interrupt();
1011 }
1012 }
1013 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001014
1015 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001016 public void topologyChanged() {
1017 //There seems to be more topology events than there should be. Lots of link
1018 //updated, port up and switch updated on what should be a fairly static topology
pingping-lina2cbfad2013-03-07 08:39:21 +08001019
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001020 boolean refreshNeeded = false;
1021 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1022 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1023 //We don't need to recalculate anything for just link updates
1024 //They happen way too frequently (may be a bug in our link discovery)
1025 refreshNeeded = true;
1026 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001027
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001028 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001029
Jonathan Hart98957bf2013-07-01 14:49:24 +12001030 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1031 synchronized (linkUpdates) {
1032 linkUpdates.add(ldu);
1033 }
1034 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001035 }
1036
1037 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001038 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001039 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001040 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001041
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001042 //TODO determine whether we need to listen for switch joins
1043 @Override
1044 public void addedSwitch(IOFSwitch sw) {
1045 //checkStatus();
1046 }
1047
1048 @Override
1049 public void removedSwitch(IOFSwitch sw) {
1050 // TODO Auto-generated method stub
1051 }
1052
1053 @Override
1054 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001055
1056 @Override
1057 public String getName() {
1058 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +08001059 }
1060}