blob: f2fc5c9b4291388e85d743e44c293df402a3d732 [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 Hart4dfc3652013-08-02 20:22:36 +120013import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120014import java.util.concurrent.BlockingQueue;
15import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120016import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120017import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120018import java.util.concurrent.ScheduledExecutorService;
19import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080020
Jonathan Hart61ba9372013-05-19 20:10:29 -070021import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070022import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120023import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080024import net.floodlightcontroller.core.module.FloodlightModuleContext;
25import net.floodlightcontroller.core.module.FloodlightModuleException;
26import net.floodlightcontroller.core.module.IFloodlightModule;
27import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120028import net.floodlightcontroller.core.util.SingletonTask;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070029import net.floodlightcontroller.devicemanager.IDeviceService;
30import net.floodlightcontroller.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120031import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080032import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120033import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080034import net.floodlightcontroller.topology.ITopologyListener;
35import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120036import net.floodlightcontroller.util.MACAddress;
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;
71import com.google.common.collect.Multimaps;
72import com.google.common.collect.SetMultimap;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120073import com.google.common.util.concurrent.ThreadFactoryBuilder;
74
Jonathan Hart1236a9b2013-06-18 22:10:05 +120075public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart4dfc3652013-08-02 20:22:36 +120076 ITopologyListener, IOFSwitchListener,
77 IArpRequester {
pingping-lina2cbfad2013-03-07 08:39:21 +080078
79 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
80
81 protected IFloodlightProviderService floodlightProvider;
82 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070083 protected ITopoRouteService topoRouteService;
84 protected IDeviceService devices;
85 protected IRestApiService restApi;
86
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120087 protected ProxyArpManager proxyArp;
88
pingping-lina2cbfad2013-03-07 08:39:21 +080089 protected static Ptree ptree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120090 protected BlockingQueue<RibUpdate> ribUpdates;
91
Jonathan Hart61ba9372013-05-19 20:10:29 -070092 protected String bgpdRestIp;
93 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120094 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070095
96 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
97 //the controller/OS should hand out cookie IDs to prevent conflicts.
98 protected final long APP_COOKIE = 0xa0000000000000L;
99 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
100 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
101 //Cookie for flows in ingress switches that rewrite the MAC address
102 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200103 //Cookie for flows that setup BGP paths
104 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200105 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
106 //need to be higher priority than this otherwise the rewrite may not get done
107 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700108
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200109 protected final short BGP_PORT = 179;
110
Jonathan Hart98957bf2013-07-01 14:49:24 +1200111 protected final int TOPO_DETECTION_WAIT = 2; //seconds
112
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200113 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200114 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200115 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200116 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200117 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200118
119 //True when all switches have connected
120 protected volatile boolean switchesConnected = false;
121 //True when we have a full mesh of shortest paths between gateways
122 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200123
Jonathan Hart98957bf2013-07-01 14:49:24 +1200124 protected ArrayList<LDUpdate> linkUpdates;
125 protected SingletonTask topologyChangeDetectorTask;
126
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200127 //protected HashMap<InetAddress, RibUpdate> prefixesWaitingOnArp;
128 //protected HashMap<InetAddress, PathUpdate> pathsWaitingOnArp;
129 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
130 protected SetMultimap<InetAddress, PathUpdate> pathsWaitingOnArp;
131
Jonathan Hart98957bf2013-07-01 14:49:24 +1200132 protected class TopologyChangeDetector implements Runnable {
133 @Override
134 public void run() {
135 log.debug("Running topology change detection task");
136 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200137 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200138 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
139
140 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200141
142 Iterator<LDUpdate> it = linkUpdates.iterator();
143 while (it.hasNext()){
144 LDUpdate ldu = it.next();
145 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
146 ldu.getDst(), ldu.getDstPort());
147
148 if (activeLinks.contains(l)){
149 log.debug("Not found: {}", l);
150 it.remove();
151 }
152 }
153 }
154
155 if (linkUpdates.isEmpty()){
156 //All updates have been seen in network map.
157 //We can check if topology is ready
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200158 log.debug("No known changes outstanding. Checking topology now");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200159 checkStatus();
160 }
161 else {
162 //We know of some link updates that haven't propagated to the database yet
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200163 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200164 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
165 }
166 }
167 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700168
Jonathan Hartd1f23252013-06-13 15:17:05 +1200169 private void readGatewaysConfiguration(String gatewaysFilename){
170 File gatewaysFile = new File(gatewaysFilename);
171 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700172
Jonathan Hartd1f23252013-06-13 15:17:05 +1200173 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200174 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
175
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200176 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200177 interfaces = new HashMap<String, Interface>();
178 for (Interface intf : config.getInterfaces()){
179 interfaces.put(intf.getName(), intf);
180 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200181 bgpPeers = new HashMap<InetAddress, BgpPeer>();
182 for (BgpPeer peer : config.getPeers()){
183 bgpPeers.put(peer.getIpAddress(), peer);
184 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200185
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200186 bgpdAttachmentPoint = new SwitchPort(
187 new Dpid(config.getBgpdAttachmentDpid()),
188 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200189
Jonathan Hartd1f23252013-06-13 15:17:05 +1200190 } catch (JsonParseException e) {
191 log.error("Error in JSON file", e);
192 System.exit(1);
193 } catch (JsonMappingException e) {
194 log.error("Error in JSON file", e);
195 System.exit(1);
196 } catch (IOException e) {
197 log.error("Error reading JSON file", e);
198 System.exit(1);
199 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700200 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800201
202 @Override
203 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700204 Collection<Class<? extends IFloodlightService>> l
205 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800206 l.add(IBgpRouteService.class);
207 return l;
208 }
209
210 @Override
211 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700212 Map<Class<? extends IFloodlightService>, IFloodlightService> m
213 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800214 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800215 return m;
216 }
217
pingping-lina2cbfad2013-03-07 08:39:21 +0800218 @Override
219 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700220 Collection<Class<? extends IFloodlightService>> l
221 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800222 l.add(IFloodlightProviderService.class);
223 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700224 l.add(IDeviceService.class);
225 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800226 return l;
227 }
228
229 @Override
230 public void init(FloodlightModuleContext context)
231 throws FloodlightModuleException {
232
233 ptree = new Ptree(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200234
235 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200236
pingping-lina2cbfad2013-03-07 08:39:21 +0800237 // Register floodlight provider and REST handler.
238 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800239 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700240 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200241 restApi = context.getServiceImpl(IRestApiService.class);
242
243 //TODO We'll initialise this here for now, but it should really be done as
244 //part of the controller core
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200245 proxyArp = new ProxyArpManager(floodlightProvider, topology, devices);
pingping-lina2cbfad2013-03-07 08:39:21 +0800246
Jonathan Hart98957bf2013-07-01 14:49:24 +1200247 linkUpdates = new ArrayList<LDUpdate>();
248 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
249 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700250
251 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200252
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200253 pathsWaitingOnArp = Multimaps.synchronizedSetMultimap(
254 HashMultimap.<InetAddress, PathUpdate>create());
255 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
256 HashMultimap.<InetAddress, RibUpdate>create());
257
Jonathan Hart61ba9372013-05-19 20:10:29 -0700258 //Read in config values
259 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
260 if (bgpdRestIp == null){
261 log.error("BgpdRestIp property not found in config file");
262 System.exit(1);
263 }
264 else {
265 log.info("BgpdRestIp set to {}", bgpdRestIp);
266 }
267
268 routerId = context.getConfigParams(this).get("RouterId");
269 if (routerId == null){
270 log.error("RouterId property not found in config file");
271 System.exit(1);
272 }
273 else {
274 log.info("RouterId set to {}", routerId);
275 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200276
Jonathan Hart9575cb62013-07-05 13:43:49 +1200277 String configFilenameParameter = context.getConfigParams(this).get("configfile");
278 if (configFilenameParameter != null){
279 configFilename = configFilenameParameter;
280 }
281 log.debug("Config file set to {}", configFilename);
282
283 readGatewaysConfiguration(configFilename);
pingping-lina2cbfad2013-03-07 08:39:21 +0800284 // Test.
285 //test();
286 }
287
288 public Ptree getPtree() {
289 return ptree;
290 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700291
292 public void clearPtree() {
293 //ptree = null;
294 ptree = new Ptree(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800295 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700296
pingping-line2a09ca2013-03-23 09:33:58 +0800297 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700298 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800299 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700300
pingping-line2a09ca2013-03-23 09:33:58 +0800301 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700302 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800303 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800304
305 // Return nexthop address as byte array.
306 public Rib lookupRib(byte[] dest) {
307 if (ptree == null) {
308 log.debug("lookupRib: ptree null");
309 return null;
310 }
311
312 PtreeNode node = ptree.match(dest, 32);
313 if (node == null) {
314 log.debug("lookupRib: ptree node null");
315 return null;
316 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700317
pingping-lina2cbfad2013-03-07 08:39:21 +0800318 if (node.rib == null) {
319 log.debug("lookupRib: ptree rib null");
320 return null;
321 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700322
pingping-lina2cbfad2013-03-07 08:39:21 +0800323 ptree.delReference(node);
324
325 return node.rib;
326 }
327
Jonathan Hart61ba9372013-05-19 20:10:29 -0700328 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800329 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700330 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800331 System.out.println("Here it is");
332 Prefix p = new Prefix("128.0.0.0", 8);
333 Prefix q = new Prefix("8.0.0.0", 8);
334 Prefix r = new Prefix("10.0.0.0", 24);
335 Prefix a = new Prefix("10.0.0.1", 32);
336
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200337 ptree.acquire(p.getAddress(), p.getPrefixLength());
338 ptree.acquire(q.getAddress(), q.getPrefixLength());
339 ptree.acquire(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800340
341 System.out.println("Traverse start");
342 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
343 Prefix p_result = new Prefix(node.key, node.keyBits);
344 }
345
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200346 PtreeNode n = ptree.match(a.getAddress(), a.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800347 if (n != null) {
348 System.out.println("Matched prefix for 10.0.0.1:");
349 Prefix x = new Prefix(n.key, n.keyBits);
350 ptree.delReference(n);
351 }
352
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200353 n = ptree.lookup(p.getAddress(), p.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800354 if (n != null) {
355 ptree.delReference(n);
356 ptree.delReference(n);
357 }
358 System.out.println("Traverse start");
359 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
360 Prefix p_result = new Prefix(node.key, node.keyBits);
361 }
362
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200363 n = ptree.lookup(q.getAddress(), q.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800364 if (n != null) {
365 ptree.delReference(n);
366 ptree.delReference(n);
367 }
368 System.out.println("Traverse start");
369 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
370 Prefix p_result = new Prefix(node.key, node.keyBits);
371 }
372
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200373 n = ptree.lookup(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800374 if (n != null) {
375 ptree.delReference(n);
376 ptree.delReference(n);
377 }
378 System.out.println("Traverse start");
379 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
380 Prefix p_result = new Prefix(node.key, node.keyBits);
381 }
382
383 }
384
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200385 private String getPrefixFromPtree(PtreeNode node){
386 InetAddress address = null;
387 try {
388 address = InetAddress.getByAddress(node.key);
389 } catch (UnknownHostException e1) {
390 //Should never happen is the reverse conversion has already been done
391 log.error("Malformed IP address");
392 return "";
393 }
394 return address.toString() + "/" + node.rib.masklen;
395 }
396
Jonathan Hart61ba9372013-05-19 20:10:29 -0700397 private void retrieveRib(){
398 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
399 String response = RestClient.get(url);
400
401 if (response.equals("")){
402 return;
403 }
404
405 response = response.replaceAll("\"", "'");
406 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
407 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
408 String router_id = jsonObj.getString("router-id");
409
410 int size = rib_json_array.size();
411
412 log.info("Retrived RIB of {} entries from BGPd", size);
413
414 for (int j = 0; j < size; j++) {
415 JSONObject second_json_object = rib_json_array.getJSONObject(j);
416 String prefix = second_json_object.getString("prefix");
417 String nexthop = second_json_object.getString("nexthop");
418
419 //insert each rib entry into the local rib;
420 String[] substring = prefix.split("/");
421 String prefix1 = substring[0];
422 String mask1 = substring[1];
423
424 Prefix p;
425 try {
426 p = new Prefix(prefix1, Integer.valueOf(mask1));
427 } catch (NumberFormatException e) {
428 log.warn("Wrong mask format in RIB JSON: {}", mask1);
429 continue;
430 } catch (UnknownHostException e1) {
431 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
432 continue;
433 }
434
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200435 PtreeNode node = ptree.acquire(p.getAddress(), p.getPrefixLength());
436 Rib rib = new Rib(router_id, nexthop, p.getPrefixLength());
Jonathan Hart61ba9372013-05-19 20:10:29 -0700437
438 if (node.rib != null) {
439 node.rib = null;
440 ptree.delReference(node);
441 }
442
443 node.rib = rib;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700444
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200445 prefixAdded(node);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700446 }
447 }
448
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200449 @Override
450 public void newRibUpdate(RibUpdate update) {
451 ribUpdates.add(update);
452 }
453
454 //TODO temporary
455 public void wrapPrefixAdded(RibUpdate update) {
456 Prefix prefix = update.getPrefix();
457
458 PtreeNode node = ptree.acquire(prefix.getAddress(), prefix.getPrefixLength());
459
460 if (node.rib != null) {
461 node.rib = null;
462 ptree.delReference(node);
463 }
464 node.rib = update.getRibEntry();
465
466 prefixAdded(node);
467 }
468
469 //TODO temporary
470 public void wrapPrefixDeleted(RibUpdate update) {
471 Prefix prefix = update.getPrefix();
472
473 PtreeNode node = ptree.lookup(prefix.getAddress(), prefix.getPrefixLength());
474
475 /*
476 * Remove the flows from the switches before the rib is lost
477 * Theory: we could get a delete for a prefix not in the Ptree.
478 * This would result in a null node being returned. We could get a delete for
479 * a node that's not actually there, but is a aggregate node. This would result
480 * in a non-null node with a null rib. Only a non-null node with a non-null
481 * rib is an actual prefix in the Ptree.
482 */
483 if (node != null && node.rib != null){
484 prefixDeleted(node);
485 }
486
487 if (node != null && node.rib != null) {
488 if (update.getRibEntry().equals(node.rib)) {
489 node.rib = null;
490 ptree.delReference(node);
491 }
492 }
493 }
494
495 @Override
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200496 public void prefixAdded(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200497 if (!topologyReady){
498 return;
499 }
500
501 String prefix = getPrefixFromPtree(node);
502
Jonathan Hartc824ad02013-07-03 15:58:45 +1200503 log.debug("New prefix {} added, next hop {}, routerId {}",
504 new Object[] {prefix, node.rib.nextHop.toString(),
505 node.rib.routerId.getHostAddress()});
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200506
Jonathan Hartc824ad02013-07-03 15:58:45 +1200507 //TODO this is wrong, we shouldn't be dealing with BGP peers here.
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200508 //We need to figure out where the device is attached and what its
Jonathan Hartc824ad02013-07-03 15:58:45 +1200509 //mac address is by learning.
510 //The next hop is not necessarily the peer, and the peer's attachment
511 //point is not necessarily the next hop's attachment point.
512 BgpPeer peer = bgpPeers.get(node.rib.nextHop);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700513
Jonathan Hartc824ad02013-07-03 15:58:45 +1200514 if (peer == null){
515 //TODO local router isn't in peers list so this will get thrown
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200516 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
Jonathan Hartc824ad02013-07-03 15:58:45 +1200517
518 //The other scenario is this is a route server route. In that
519 //case the next hop is not in our configuration
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200520 log.error("Couldn't find next hop router in router {} in config"
521 , node.rib.nextHop.toString());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700522 return; //just quit out here? This is probably a configuration error
523 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200524
525 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200526
Jonathan Hartc824ad02013-07-03 15:58:45 +1200527 //Add a flow to rewrite mac for this prefix to all border switches
528 for (Interface srcInterface : interfaces.values()) {
529 if (srcInterface == peerInterface) {
530 //Don't push a flow for the switch where this peer is attached
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700531 continue;
532 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200533
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700534 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200535 srcInterface.getSwitchPort(),
536 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700537
538 if (shortestPath == null){
539 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200540 srcInterface.getSwitchPort(),
541 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700542 return; // just quit here?
543 }
544
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700545 //Set up the flow mod
546 OFFlowMod fm =
547 (OFFlowMod) floodlightProvider.getOFMessageFactory()
548 .getMessage(OFType.FLOW_MOD);
549
550 fm.setIdleTimeout((short)0)
551 .setHardTimeout((short)0)
552 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
553 .setCookie(MAC_RW_COOKIE)
554 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200555 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700556 .setLengthU(OFFlowMod.MINIMUM_LENGTH
557 + OFActionDataLayerDestination.MINIMUM_LENGTH
558 + OFActionOutput.MINIMUM_LENGTH);
559
560 OFMatch match = new OFMatch();
561 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200562 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700563
Jonathan Hartc824ad02013-07-03 15:58:45 +1200564 //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
565 //match.setDataLayerSource(peer.getMacAddress().toBytes());
566 //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200567
568 InetAddress address = null;
569 try {
570 address = InetAddress.getByAddress(node.key);
571 } catch (UnknownHostException e1) {
572 //Should never happen is the reverse conversion has already been done
573 log.error("Malformed IP address");
574 return;
575 }
576
577 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
578 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700579
580 //Set up MAC rewrite action
581 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200582 //TODO use ARP module rather than configured mac addresses
583 //TODO the peer's mac address is not necessarily the next hop's...
584 macRewriteAction.setDataLayerAddress(peer.getMacAddress().toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700585
586 //Set up output action
587 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200588 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700589
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200590 Port outputPort = shortestPath.flowEntries().get(0).outPort();
591 outputAction.setPort(outputPort.value());
592
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700593 List<OFAction> actions = new ArrayList<OFAction>();
594 actions.add(macRewriteAction);
595 actions.add(outputAction);
596 fm.setActions(actions);
597
598 //Write to switch
599 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200600 .get(srcInterface.getDpid());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700601
602 if (sw == null){
603 log.warn("Switch not found when pushing flow mod");
604 continue;
605 }
606
607 List<OFMessage> msglist = new ArrayList<OFMessage>();
608 msglist.add(fm);
609 try {
610 sw.write(msglist, null);
611 sw.flush();
612 } catch (IOException e) {
613 log.error("Failure writing flow mod", e);
614 }
615 }
616 }
617
Jonathan Hartc824ad02013-07-03 15:58:45 +1200618 //TODO this is largely untested
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200619 @Override
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200620 public void prefixDeleted(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200621 if (!topologyReady) {
622 return;
623 }
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200624
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200625 String prefix = getPrefixFromPtree(node);
626
627 log.debug("Prefix {} deleted, next hop {}",
628 prefix, node.rib.nextHop.toString());
629
630 //Remove MAC rewriting flows from other border switches
Jonathan Hartc824ad02013-07-03 15:58:45 +1200631 BgpPeer peer = bgpPeers.get(node.rib.nextHop);
632 if (peer == null){
633 //either a router server route or local route. Can't handle right now
634 return;
635 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200636
Jonathan Hartc824ad02013-07-03 15:58:45 +1200637 Interface peerInterface = interfaces.get(peer.getInterfaceName());
638
639 for (Interface srcInterface : interfaces.values()) {
640 if (srcInterface == peerInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200641 continue;
642 }
643
644 //Set up the flow mod
645 OFFlowMod fm =
646 (OFFlowMod) floodlightProvider.getOFMessageFactory()
647 .getMessage(OFType.FLOW_MOD);
648
649 fm.setIdleTimeout((short)0)
650 .setHardTimeout((short)0)
651 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
652 .setCookie(MAC_RW_COOKIE)
653 .setCommand(OFFlowMod.OFPFC_DELETE)
Jonathan Hart9575cb62013-07-05 13:43:49 +1200654 .setOutPort(OFPort.OFPP_NONE)
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200655 .setPriority(SDNIP_PRIORITY)
656 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
657 //+ OFActionDataLayerDestination.MINIMUM_LENGTH
658 //+ OFActionOutput.MINIMUM_LENGTH);
659
660 OFMatch match = new OFMatch();
661 match.setDataLayerType(Ethernet.TYPE_IPv4);
662 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
663
Jonathan Hartc824ad02013-07-03 15:58:45 +1200664 //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
665 //match.setDataLayerSource(peer.getMacAddress().toBytes());
666 //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200667
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200668 InetAddress address = null;
669 try {
670 address = InetAddress.getByAddress(node.key);
671 } catch (UnknownHostException e1) {
672 //Should never happen is the reverse conversion has already been done
673 log.error("Malformed IP address");
674 return;
675 }
676
677 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
678 fm.setMatch(match);
679
680 //Write to switch
681 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200682 .get(srcInterface.getDpid());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200683
684 if (sw == null){
685 log.warn("Switch not found when pushing flow mod");
686 continue;
687 }
688
689 List<OFMessage> msglist = new ArrayList<OFMessage>();
690 msglist.add(fm);
691 try {
692 sw.write(msglist, null);
693 sw.flush();
694 } catch (IOException e) {
695 log.error("Failure writing flow mod", e);
696 }
697 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700698 }
699
700 /*
701 * On startup we need to calculate a full mesh of paths between all gateway
702 * switches
703 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200704 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700705 //For each border router, calculate and install a path from every other
706 //border switch to said border router. However, don't install the entry
707 //in to the first hop switch, as we need to install an entry to rewrite
708 //for each prefix received. This will be done later when prefixes have
709 //actually been received.
710
Jonathan Hartc824ad02013-07-03 15:58:45 +1200711 for (BgpPeer peer : bgpPeers.values()) {
712 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200713
714 //See if we know the MAC address of the peer. If not we can't
715 //do anything until we learn it
716 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
717 if (mac == null) {
718 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
719 //Put in the pending paths list first
720 pathsWaitingOnArp.put(peer.getIpAddress(),
721 new PathUpdate(peerInterface, peer.getIpAddress()));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700722
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200723 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
724 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700725 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200726
727 //If we know the MAC, lets go ahead and push the paths to this peer
728 calculateAndPushPath(peerInterface, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700729 }
730 }
731
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200732 private void calculateAndPushPath(Interface dstInterface, MACAddress dstMacAddress) {
733 for (Interface srcInterface : interfaces.values()) {
734 if (dstInterface.equals(srcInterface.getName())){
735 continue;
736 }
737
738 DataPath shortestPath = topoRouteService.getShortestPath(
739 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
740
741 if (shortestPath == null){
742 log.debug("Shortest path between {} and {} not found",
743 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
744 return; // just quit here?
745 }
746
747 //install flows
748 installPath(shortestPath.flowEntries(), dstMacAddress);
749 }
750 }
751
752 private void installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700753 //Set up the flow mod
754 OFFlowMod fm =
755 (OFFlowMod) floodlightProvider.getOFMessageFactory()
756 .getMessage(OFType.FLOW_MOD);
757
758 OFActionOutput action = new OFActionOutput();
759 action.setMaxLength((short)0xffff);
760 List<OFAction> actions = new ArrayList<OFAction>();
761 actions.add(action);
762
763 fm.setIdleTimeout((short)0)
764 .setHardTimeout((short)0)
765 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
766 .setCookie(L2_FWD_COOKIE)
767 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700768 .setActions(actions)
769 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
770
771 //Don't push the first flow entry. We need to push entries in the
772 //first switch based on IP prefix which we don't know yet.
773 for (int i = 1; i < flowEntries.size(); i++){
774 FlowEntry flowEntry = flowEntries.get(i);
775
776 OFMatch match = new OFMatch();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200777 //TODO Again using MAC address from configuration
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200778 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700779 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
780 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
781
782 fm.setMatch(match);
783
784 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
785
786 if (sw == null){
787 log.warn("Switch not found when pushing flow mod");
788 continue;
789 }
790
791 List<OFMessage> msglist = new ArrayList<OFMessage>();
792 msglist.add(fm);
793 try {
794 sw.write(msglist, null);
795 sw.flush();
796 } catch (IOException e) {
797 log.error("Failure writing flow mod", e);
798 }
799
800 try {
801 fm = fm.clone();
802 } catch (CloneNotSupportedException e1) {
803 log.error("Failure cloning flow mod", e1);
804 }
805 }
806 }
807
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200808 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200809 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200810 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
811
812 DataPath path = topoRouteService.getShortestPath(
813 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
814
815 if (path == null){
816 log.debug("Unable to compute path for BGP traffic for {}",
817 bgpPeer.getIpAddress());
818 continue;
819 }
820
821 //Set up the flow mod
822 OFFlowMod fm =
823 (OFFlowMod) floodlightProvider.getOFMessageFactory()
824 .getMessage(OFType.FLOW_MOD);
825
826 OFActionOutput action = new OFActionOutput();
827 action.setMaxLength((short)0xffff);
828 List<OFAction> actions = new ArrayList<OFAction>();
829 actions.add(action);
830
831 fm.setIdleTimeout((short)0)
832 .setHardTimeout((short)0)
833 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
834 .setCookie(BGP_COOKIE)
835 .setCommand(OFFlowMod.OFPFC_ADD)
836 .setPriority(SDNIP_PRIORITY)
837 .setActions(actions)
838 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
839
840 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
841 OFMatch forwardMatchSrc = new OFMatch();
842
843
844 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
845 + "/32";
846 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
847 + "/32";
848
849 //Common match fields
850 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
851 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
852 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
853 forwardMatchSrc.setTransportDestination(BGP_PORT);
854 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
855 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
856
857
858 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
859
860 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
861 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
862
863 OFMatch forwardMatchDst = forwardMatchSrc.clone();
864
865 forwardMatchSrc.setTransportSource(BGP_PORT);
866 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
867 forwardMatchDst.setTransportDestination(BGP_PORT);
868 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
869
870 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
871 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
872
873 OFMatch reverseMatchDst = reverseMatchSrc.clone();
874
875 reverseMatchSrc.setTransportSource(BGP_PORT);
876 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
877 reverseMatchDst.setTransportDestination(BGP_PORT);
878 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
879
880 fm.setMatch(forwardMatchSrc);
881
882 for (FlowEntry flowEntry : path.flowEntries()){
883 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
884 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
885 try {
886 forwardFlowModSrc = fm.clone();
887 forwardFlowModDst = fm.clone();
888 reverseFlowModSrc = fm.clone();
889 reverseFlowModDst = fm.clone();
890 } catch (CloneNotSupportedException e) {
891 log.warn("Clone failed", e);
892 continue;
893 }
894
895 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
896 forwardFlowModSrc.setMatch(forwardMatchSrc);
897 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
898 .setPort(flowEntry.outPort().value());
899
900 forwardMatchDst.setInputPort(flowEntry.inPort().value());
901 forwardFlowModDst.setMatch(forwardMatchDst);
902 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
903 .setPort(flowEntry.outPort().value());
904
905 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
906 reverseFlowModSrc.setMatch(reverseMatchSrc);
907 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
908 .setPort(flowEntry.inPort().value());
909
910 reverseMatchDst.setInputPort(flowEntry.outPort().value());
911 reverseFlowModDst.setMatch(reverseMatchDst);
912 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
913 .setPort(flowEntry.inPort().value());
914
915 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
916
917 //Hopefully the switch is there
918 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
919 msgList.add(forwardFlowModSrc);
920 msgList.add(forwardFlowModDst);
921 msgList.add(reverseFlowModSrc);
922 msgList.add(reverseFlowModDst);
923
924 try {
925 sw.write(msgList, null);
926 sw.flush();
927 } catch (IOException e) {
928 log.error("Failure writing flow mod", e);
929 }
930 }
931 }
932 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200933
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200934 @Override
935 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
936 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
937 MACAddress.valueOf(macAddress).toString());
938
939 Set<PathUpdate> pathsToPush = pathsWaitingOnArp.removeAll(ipAddress);
940
941 for (PathUpdate update : pathsToPush) {
942 log.debug("Pushing path to {} at {} on {}", new Object[] {
943 update.getDstIpAddress().getHostAddress(),
944 MACAddress.valueOf(macAddress),
945 update.getDstInterface().getSwitchPort()});
946 calculateAndPushPath(update.getDstInterface(),
947 MACAddress.valueOf(macAddress));
948 }
949 }
950
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200951 private void beginRouting(){
952 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200953 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200954 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200955
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200956 //Traverse ptree and create flows for all routes
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200957 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
958 if (node.rib != null){
959 prefixAdded(node);
960 }
961 }
962 }
963
964 private void checkSwitchesConnected(){
965 for (String dpid : switches){
966 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
967 log.debug("Not all switches are here yet");
968 return;
969 }
970 }
971 switchesConnected = true;
972 }
973
Jonathan Hartc824ad02013-07-03 15:58:45 +1200974 //Actually we only need to go half way round to verify full mesh connectivity
975 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200976 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200977 for (Interface dstInterface : interfaces.values()) {
978 for (Interface srcInterface : interfaces.values()) {
979 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200980 continue;
981 }
982
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200983 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200984 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200985
986 if (shortestPath == null){
987 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200988 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200989 return;
990 }
991 }
992 }
993 topologyReady = true;
994 }
995
996 private void checkStatus(){
997 log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
998
999 if (!switchesConnected){
1000 checkSwitchesConnected();
1001 }
1002 boolean oldTopologyReadyStatus = topologyReady;
1003 if (switchesConnected && !topologyReady){
1004 checkTopologyReady();
1005 }
1006 if (!oldTopologyReadyStatus && topologyReady){
1007 beginRouting();
1008 }
1009 }
1010
pingping-lina2cbfad2013-03-07 08:39:21 +08001011 @Override
1012 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +08001013 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001014 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -07001015 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +08001016
Jonathan Hartc7ca35d2013-06-25 20:54:25 +12001017 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
1018
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001019 ExecutorService e = Executors.newSingleThreadExecutor(
1020 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
1021
1022
1023 e.execute(new Runnable() {
1024 @Override
1025 public void run() {
1026 doUpdatesThread();
1027 }
1028 });
1029
Jonathan Hart61ba9372013-05-19 20:10:29 -07001030 //Retrieve the RIB from BGPd during startup
1031 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +08001032 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001033
1034 private void doUpdatesThread() {
1035 boolean interrupted = false;
1036 try {
1037 while (true) {
1038 try {
1039 RibUpdate update = ribUpdates.take();
1040 switch (update.getOperation()){
1041 case UPDATE:
1042 wrapPrefixAdded(update);
1043 break;
1044 case DELETE:
1045 wrapPrefixDeleted(update);
1046 break;
1047 }
1048 } catch (InterruptedException e) {
1049 interrupted = true;
1050 }
1051 }
1052 } finally {
1053 if (interrupted) {
1054 Thread.currentThread().interrupt();
1055 }
1056 }
1057 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001058
1059 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001060 public void topologyChanged() {
1061 //There seems to be more topology events than there should be. Lots of link
1062 //updated, port up and switch updated on what should be a fairly static topology
pingping-lina2cbfad2013-03-07 08:39:21 +08001063
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001064 boolean refreshNeeded = false;
1065 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1066 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1067 //We don't need to recalculate anything for just link updates
1068 //They happen way too frequently (may be a bug in our link discovery)
1069 refreshNeeded = true;
1070 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001071
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001072 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001073
Jonathan Hart98957bf2013-07-01 14:49:24 +12001074 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1075 synchronized (linkUpdates) {
1076 linkUpdates.add(ldu);
1077 }
1078 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001079 }
1080
1081 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001082 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001083 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001084 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001085
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001086 //TODO determine whether we need to listen for switch joins
1087 @Override
1088 public void addedSwitch(IOFSwitch sw) {
1089 //checkStatus();
1090 }
1091
1092 @Override
1093 public void removedSwitch(IOFSwitch sw) {
1094 // TODO Auto-generated method stub
1095 }
1096
1097 @Override
1098 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001099
1100 @Override
1101 public String getName() {
1102 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +08001103 }
1104}