blob: f4ff6b1f5f8ca02f118540c31fa3346bde82012c [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 Hart0ee0f022013-08-03 22:21:54 +120037import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
Jonathan Hart98957bf2013-07-01 14:49:24 +120038import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070039import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120040import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070041import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
42import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120043import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120044import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070045import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070046import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120047import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070048import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070049import net.onrc.onos.ofcontroller.util.Port;
50import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080051import net.sf.json.JSONArray;
52import net.sf.json.JSONObject;
53import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080054
Jonathan Hartd1f23252013-06-13 15:17:05 +120055import org.codehaus.jackson.JsonParseException;
56import org.codehaus.jackson.map.JsonMappingException;
57import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070058import org.openflow.protocol.OFFlowMod;
59import org.openflow.protocol.OFMatch;
60import org.openflow.protocol.OFMessage;
61import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120062import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070063import org.openflow.protocol.OFType;
64import org.openflow.protocol.action.OFAction;
65import org.openflow.protocol.action.OFActionDataLayerDestination;
66import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120067import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080068import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
Jonathan Hart4dfc3652013-08-02 20:22:36 +120071import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120072import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120073import com.google.common.collect.Multimaps;
74import com.google.common.collect.SetMultimap;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120075import com.google.common.util.concurrent.ThreadFactoryBuilder;
76
Jonathan Hart1236a9b2013-06-18 22:10:05 +120077public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart4dfc3652013-08-02 20:22:36 +120078 ITopologyListener, IOFSwitchListener,
79 IArpRequester {
pingping-lina2cbfad2013-03-07 08:39:21 +080080
81 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
82
83 protected IFloodlightProviderService floodlightProvider;
84 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070085 protected ITopoRouteService topoRouteService;
86 protected IDeviceService devices;
87 protected IRestApiService restApi;
88
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120089 protected ProxyArpManager proxyArp;
90
pingping-lina2cbfad2013-03-07 08:39:21 +080091 protected static Ptree ptree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120092 protected BlockingQueue<RibUpdate> ribUpdates;
93
Jonathan Hart61ba9372013-05-19 20:10:29 -070094 protected String bgpdRestIp;
95 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120096 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070097
98 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
99 //the controller/OS should hand out cookie IDs to prevent conflicts.
100 protected final long APP_COOKIE = 0xa0000000000000L;
101 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
102 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
103 //Cookie for flows in ingress switches that rewrite the MAC address
104 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200105 //Cookie for flows that setup BGP paths
106 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200107 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
108 //need to be higher priority than this otherwise the rewrite may not get done
109 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700110
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200111 protected final short BGP_PORT = 179;
112
Jonathan Hart98957bf2013-07-01 14:49:24 +1200113 protected final int TOPO_DETECTION_WAIT = 2; //seconds
114
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200115 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200116 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200117 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200118 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200119 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200120
121 //True when all switches have connected
122 protected volatile boolean switchesConnected = false;
123 //True when we have a full mesh of shortest paths between gateways
124 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200125
Jonathan Hart98957bf2013-07-01 14:49:24 +1200126 protected ArrayList<LDUpdate> linkUpdates;
127 protected SingletonTask topologyChangeDetectorTask;
128
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200129 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
130 protected SetMultimap<InetAddress, PathUpdate> pathsWaitingOnArp;
131
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200132 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
133
134 private class PushedFlowMod {
135 private long dpid;
136 private OFFlowMod flowMod;
137
138 public PushedFlowMod(long dpid, OFFlowMod flowMod) {
139 this.dpid = dpid;
140 this.flowMod = flowMod;
141 }
142
143 public long getDpid() {
144 return dpid;
145 }
146
147 public OFFlowMod getFlowMod() {
148 return flowMod;
149 }
150 }
151
Jonathan Hart98957bf2013-07-01 14:49:24 +1200152 protected class TopologyChangeDetector implements Runnable {
153 @Override
154 public void run() {
155 log.debug("Running topology change detection task");
156 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200157 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200158 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
159
160 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200161
162 Iterator<LDUpdate> it = linkUpdates.iterator();
163 while (it.hasNext()){
164 LDUpdate ldu = it.next();
165 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
166 ldu.getDst(), ldu.getDstPort());
167
168 if (activeLinks.contains(l)){
169 log.debug("Not found: {}", l);
170 it.remove();
171 }
172 }
173 }
174
175 if (linkUpdates.isEmpty()){
176 //All updates have been seen in network map.
177 //We can check if topology is ready
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200178 log.debug("No known changes outstanding. Checking topology now");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200179 checkStatus();
180 }
181 else {
182 //We know of some link updates that haven't propagated to the database yet
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200183 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200184 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
185 }
186 }
187 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700188
Jonathan Hartd1f23252013-06-13 15:17:05 +1200189 private void readGatewaysConfiguration(String gatewaysFilename){
190 File gatewaysFile = new File(gatewaysFilename);
191 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700192
Jonathan Hartd1f23252013-06-13 15:17:05 +1200193 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200194 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
195
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200196 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200197 interfaces = new HashMap<String, Interface>();
198 for (Interface intf : config.getInterfaces()){
199 interfaces.put(intf.getName(), intf);
200 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200201 bgpPeers = new HashMap<InetAddress, BgpPeer>();
202 for (BgpPeer peer : config.getPeers()){
203 bgpPeers.put(peer.getIpAddress(), peer);
204 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200205
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200206 bgpdAttachmentPoint = new SwitchPort(
207 new Dpid(config.getBgpdAttachmentDpid()),
208 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200209
Jonathan Hartd1f23252013-06-13 15:17:05 +1200210 } catch (JsonParseException e) {
211 log.error("Error in JSON file", e);
212 System.exit(1);
213 } catch (JsonMappingException e) {
214 log.error("Error in JSON file", e);
215 System.exit(1);
216 } catch (IOException e) {
217 log.error("Error reading JSON file", e);
218 System.exit(1);
219 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700220 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800221
222 @Override
223 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700224 Collection<Class<? extends IFloodlightService>> l
225 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800226 l.add(IBgpRouteService.class);
227 return l;
228 }
229
230 @Override
231 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700232 Map<Class<? extends IFloodlightService>, IFloodlightService> m
233 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800234 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800235 return m;
236 }
237
pingping-lina2cbfad2013-03-07 08:39:21 +0800238 @Override
239 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700240 Collection<Class<? extends IFloodlightService>> l
241 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800242 l.add(IFloodlightProviderService.class);
243 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700244 l.add(IDeviceService.class);
245 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800246 return l;
247 }
248
249 @Override
250 public void init(FloodlightModuleContext context)
251 throws FloodlightModuleException {
252
253 ptree = new Ptree(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200254
255 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200256
pingping-lina2cbfad2013-03-07 08:39:21 +0800257 // Register floodlight provider and REST handler.
258 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800259 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700260 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200261 restApi = context.getServiceImpl(IRestApiService.class);
262
263 //TODO We'll initialise this here for now, but it should really be done as
264 //part of the controller core
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200265 proxyArp = new ProxyArpManager(floodlightProvider, topology, devices);
pingping-lina2cbfad2013-03-07 08:39:21 +0800266
Jonathan Hart98957bf2013-07-01 14:49:24 +1200267 linkUpdates = new ArrayList<LDUpdate>();
268 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
269 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700270
271 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200272
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200273 pathsWaitingOnArp = Multimaps.synchronizedSetMultimap(
274 HashMultimap.<InetAddress, PathUpdate>create());
275 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
276 HashMultimap.<InetAddress, RibUpdate>create());
277
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200278 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
279
Jonathan Hart61ba9372013-05-19 20:10:29 -0700280 //Read in config values
281 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
282 if (bgpdRestIp == null){
283 log.error("BgpdRestIp property not found in config file");
284 System.exit(1);
285 }
286 else {
287 log.info("BgpdRestIp set to {}", bgpdRestIp);
288 }
289
290 routerId = context.getConfigParams(this).get("RouterId");
291 if (routerId == null){
292 log.error("RouterId property not found in config file");
293 System.exit(1);
294 }
295 else {
296 log.info("RouterId set to {}", routerId);
297 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200298
Jonathan Hart9575cb62013-07-05 13:43:49 +1200299 String configFilenameParameter = context.getConfigParams(this).get("configfile");
300 if (configFilenameParameter != null){
301 configFilename = configFilenameParameter;
302 }
303 log.debug("Config file set to {}", configFilename);
304
305 readGatewaysConfiguration(configFilename);
pingping-lina2cbfad2013-03-07 08:39:21 +0800306 // Test.
307 //test();
308 }
309
310 public Ptree getPtree() {
311 return ptree;
312 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700313
314 public void clearPtree() {
315 //ptree = null;
316 ptree = new Ptree(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800317 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700318
pingping-line2a09ca2013-03-23 09:33:58 +0800319 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700320 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800321 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700322
pingping-line2a09ca2013-03-23 09:33:58 +0800323 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700324 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800325 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800326
327 // Return nexthop address as byte array.
328 public Rib lookupRib(byte[] dest) {
329 if (ptree == null) {
330 log.debug("lookupRib: ptree null");
331 return null;
332 }
333
334 PtreeNode node = ptree.match(dest, 32);
335 if (node == null) {
336 log.debug("lookupRib: ptree node null");
337 return null;
338 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700339
pingping-lina2cbfad2013-03-07 08:39:21 +0800340 if (node.rib == null) {
341 log.debug("lookupRib: ptree rib null");
342 return null;
343 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700344
pingping-lina2cbfad2013-03-07 08:39:21 +0800345 ptree.delReference(node);
346
347 return node.rib;
348 }
349
Jonathan Hart61ba9372013-05-19 20:10:29 -0700350 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800351 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700352 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800353 System.out.println("Here it is");
354 Prefix p = new Prefix("128.0.0.0", 8);
355 Prefix q = new Prefix("8.0.0.0", 8);
356 Prefix r = new Prefix("10.0.0.0", 24);
357 Prefix a = new Prefix("10.0.0.1", 32);
358
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200359 ptree.acquire(p.getAddress(), p.getPrefixLength());
360 ptree.acquire(q.getAddress(), q.getPrefixLength());
361 ptree.acquire(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800362
363 System.out.println("Traverse start");
364 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
365 Prefix p_result = new Prefix(node.key, node.keyBits);
366 }
367
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200368 PtreeNode n = ptree.match(a.getAddress(), a.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800369 if (n != null) {
370 System.out.println("Matched prefix for 10.0.0.1:");
371 Prefix x = new Prefix(n.key, n.keyBits);
372 ptree.delReference(n);
373 }
374
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200375 n = ptree.lookup(p.getAddress(), p.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800376 if (n != null) {
377 ptree.delReference(n);
378 ptree.delReference(n);
379 }
380 System.out.println("Traverse start");
381 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
382 Prefix p_result = new Prefix(node.key, node.keyBits);
383 }
384
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200385 n = ptree.lookup(q.getAddress(), q.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800386 if (n != null) {
387 ptree.delReference(n);
388 ptree.delReference(n);
389 }
390 System.out.println("Traverse start");
391 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
392 Prefix p_result = new Prefix(node.key, node.keyBits);
393 }
394
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200395 n = ptree.lookup(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800396 if (n != null) {
397 ptree.delReference(n);
398 ptree.delReference(n);
399 }
400 System.out.println("Traverse start");
401 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
402 Prefix p_result = new Prefix(node.key, node.keyBits);
403 }
404
405 }
406
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200407 //TODO once the Ptree is object oriented this can go
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200408 private String getPrefixFromPtree(PtreeNode node){
409 InetAddress address = null;
410 try {
411 address = InetAddress.getByAddress(node.key);
412 } catch (UnknownHostException e1) {
413 //Should never happen is the reverse conversion has already been done
414 log.error("Malformed IP address");
415 return "";
416 }
417 return address.toString() + "/" + node.rib.masklen;
418 }
419
Jonathan Hart61ba9372013-05-19 20:10:29 -0700420 private void retrieveRib(){
421 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
422 String response = RestClient.get(url);
423
424 if (response.equals("")){
425 return;
426 }
427
428 response = response.replaceAll("\"", "'");
429 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
430 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
431 String router_id = jsonObj.getString("router-id");
432
433 int size = rib_json_array.size();
434
435 log.info("Retrived RIB of {} entries from BGPd", size);
436
437 for (int j = 0; j < size; j++) {
438 JSONObject second_json_object = rib_json_array.getJSONObject(j);
439 String prefix = second_json_object.getString("prefix");
440 String nexthop = second_json_object.getString("nexthop");
441
442 //insert each rib entry into the local rib;
443 String[] substring = prefix.split("/");
444 String prefix1 = substring[0];
445 String mask1 = substring[1];
446
447 Prefix p;
448 try {
449 p = new Prefix(prefix1, Integer.valueOf(mask1));
450 } catch (NumberFormatException e) {
451 log.warn("Wrong mask format in RIB JSON: {}", mask1);
452 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200453 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700454 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
455 continue;
456 }
457
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200458 PtreeNode node = ptree.acquire(p.getAddress(), p.getPrefixLength());
459 Rib rib = new Rib(router_id, nexthop, p.getPrefixLength());
Jonathan Hart61ba9372013-05-19 20:10:29 -0700460
461 if (node.rib != null) {
462 node.rib = null;
463 ptree.delReference(node);
464 }
465
466 node.rib = rib;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700467
Jonathan Hart2f740782013-08-04 00:49:21 +1200468 addPrefixFlows(p, rib);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700469 }
470 }
471
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200472 @Override
473 public void newRibUpdate(RibUpdate update) {
474 ribUpdates.add(update);
475 }
476
Jonathan Hart2f740782013-08-04 00:49:21 +1200477 public void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200478 Prefix prefix = update.getPrefix();
479
480 PtreeNode node = ptree.acquire(prefix.getAddress(), prefix.getPrefixLength());
481
482 if (node.rib != null) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200483 //There was an existing nexthop for this prefix. This update supersedes that,
484 //so we need to remove the old flows for this prefix from the switches
485 deletePrefixFlows(prefix);
486
487 //Then remove the old nexthop from the Ptree
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200488 node.rib = null;
489 ptree.delReference(node);
490 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200491
492 //Put the new nexthop in the Ptree
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200493 node.rib = update.getRibEntry();
494
Jonathan Hart2f740782013-08-04 00:49:21 +1200495 //Push flows for the new <prefix, nexthop>
Jonathan Hart2f740782013-08-04 00:49:21 +1200496 addPrefixFlows(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200497 }
498
Jonathan Hart2f740782013-08-04 00:49:21 +1200499 public void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200500 Prefix prefix = update.getPrefix();
501
502 PtreeNode node = ptree.lookup(prefix.getAddress(), prefix.getPrefixLength());
503
504 /*
505 * Remove the flows from the switches before the rib is lost
506 * Theory: we could get a delete for a prefix not in the Ptree.
507 * This would result in a null node being returned. We could get a delete for
508 * a node that's not actually there, but is a aggregate node. This would result
509 * in a non-null node with a null rib. Only a non-null node with a non-null
510 * rib is an actual prefix in the Ptree.
511 */
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200512
513 if (node != null && node.rib != null) {
514 if (update.getRibEntry().equals(node.rib)) {
515 node.rib = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200516 ptree.delReference(node);
517
Jonathan Hart2f740782013-08-04 00:49:21 +1200518 deletePrefixFlows(update.getPrefix());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200519 }
520 }
521 }
522
Jonathan Hart2f740782013-08-04 00:49:21 +1200523 //TODO compatibility layer, used by beginRouting()
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200524 public void prefixAdded(PtreeNode node) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200525 Prefix prefix = null;
526 try {
527 prefix = new Prefix(node.key, node.rib.masklen);
Jonathan Hart32e18222013-08-07 22:05:42 +1200528 } catch (IllegalArgumentException e) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200529 log.error(" ", e);
530 }
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200531
Jonathan Hart2f740782013-08-04 00:49:21 +1200532 addPrefixFlows(prefix, node.rib);
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200533 }
534
Jonathan Hart2f740782013-08-04 00:49:21 +1200535 private void addPrefixFlows(Prefix prefix, Rib rib) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200536 if (!topologyReady){
537 return;
538 }
539
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200540 //TODO before we do anything, we have to check that the RIB entry is still in the
541 //Ptree because it could have been removed while we were waiting for ARP.
542 //I think we'll have to make prefixAdded and prefixDelete atomic as well
543 //to protect against the prefix getting deleted while where trying to add it
Jonathan Hart2f740782013-08-04 00:49:21 +1200544
Jonathan Hartc824ad02013-07-03 15:58:45 +1200545 log.debug("New prefix {} added, next hop {}, routerId {}",
Jonathan Hart2f740782013-08-04 00:49:21 +1200546 new Object[] {prefix, rib.nextHop.getHostAddress(),
547 rib.routerId.getHostAddress()});
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200548
Jonathan Hartc824ad02013-07-03 15:58:45 +1200549 //TODO this is wrong, we shouldn't be dealing with BGP peers here.
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200550 //We need to figure out where the device is attached and what its
Jonathan Hartc824ad02013-07-03 15:58:45 +1200551 //mac address is by learning.
552 //The next hop is not necessarily the peer, and the peer's attachment
553 //point is not necessarily the next hop's attachment point.
Jonathan Hart2f740782013-08-04 00:49:21 +1200554 BgpPeer peer = bgpPeers.get(rib.nextHop);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700555
Jonathan Hartc824ad02013-07-03 15:58:45 +1200556 if (peer == null){
557 //TODO local router isn't in peers list so this will get thrown
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200558 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
Jonathan Hartc824ad02013-07-03 15:58:45 +1200559
560 //The other scenario is this is a route server route. In that
561 //case the next hop is not in our configuration
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200562 log.error("Couldn't find next hop router in router {} in config",
Jonathan Hart2f740782013-08-04 00:49:21 +1200563 rib.nextHop.getHostAddress());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700564 return; //just quit out here? This is probably a configuration error
565 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200566
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200567 //Get MAC address for peer from the ARP module
568 //TODO separate out the 'ask for MAC' bit to another method
569 byte[] peerMacAddress = proxyArp.getMacAddress(peer.getIpAddress());
570 if (peerMacAddress == null) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200571 //A RibUpdate is still a nice way to package them up
572 prefixesWaitingOnArp.put(peer.getIpAddress(),
573 new RibUpdate(Operation.UPDATE, prefix, rib));
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200574 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
575 return;
576 }
577
Jonathan Hartc824ad02013-07-03 15:58:45 +1200578 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200579
Jonathan Hartc824ad02013-07-03 15:58:45 +1200580 //Add a flow to rewrite mac for this prefix to all border switches
581 for (Interface srcInterface : interfaces.values()) {
582 if (srcInterface == peerInterface) {
583 //Don't push a flow for the switch where this peer is attached
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700584 continue;
585 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200586
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700587 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200588 srcInterface.getSwitchPort(),
589 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700590
591 if (shortestPath == null){
592 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200593 srcInterface.getSwitchPort(),
594 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700595 return; // just quit here?
596 }
597
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700598 //Set up the flow mod
599 OFFlowMod fm =
600 (OFFlowMod) floodlightProvider.getOFMessageFactory()
601 .getMessage(OFType.FLOW_MOD);
602
603 fm.setIdleTimeout((short)0)
604 .setHardTimeout((short)0)
605 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
606 .setCookie(MAC_RW_COOKIE)
607 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200608 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700609 .setLengthU(OFFlowMod.MINIMUM_LENGTH
610 + OFActionDataLayerDestination.MINIMUM_LENGTH
611 + OFActionOutput.MINIMUM_LENGTH);
612
613 OFMatch match = new OFMatch();
614 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200615 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700616
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200617 InetAddress address = null;
618 try {
Jonathan Hart2f740782013-08-04 00:49:21 +1200619 address = InetAddress.getByAddress(prefix.getAddress());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200620 } catch (UnknownHostException e1) {
621 //Should never happen is the reverse conversion has already been done
622 log.error("Malformed IP address");
623 return;
624 }
625
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200626 match.setFromCIDR(address.getHostAddress() + "/" +
Jonathan Hart2f740782013-08-04 00:49:21 +1200627 prefix.getPrefixLength(), OFMatch.STR_NW_DST);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200628 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700629
630 //Set up MAC rewrite action
631 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200632 //TODO the peer's mac address is not necessarily the next hop's...
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200633 macRewriteAction.setDataLayerAddress(peerMacAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700634
635 //Set up output action
636 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200637 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700638
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200639 Port outputPort = shortestPath.flowEntries().get(0).outPort();
640 outputAction.setPort(outputPort.value());
641
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700642 List<OFAction> actions = new ArrayList<OFAction>();
643 actions.add(macRewriteAction);
644 actions.add(outputAction);
645 fm.setActions(actions);
646
647 //Write to switch
648 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200649 .get(srcInterface.getDpid());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700650
651 if (sw == null){
652 log.warn("Switch not found when pushing flow mod");
653 continue;
654 }
655
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200656 //TODO if prefix Added/Deleted are synchronized this shouldn't have to be
Jonathan Hart2f740782013-08-04 00:49:21 +1200657 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200658
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700659 List<OFMessage> msglist = new ArrayList<OFMessage>();
660 msglist.add(fm);
661 try {
662 sw.write(msglist, null);
663 sw.flush();
664 } catch (IOException e) {
665 log.error("Failure writing flow mod", e);
666 }
667 }
668 }
669
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200670 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200671 //TODO check delete/add synchronization
Jonathan Hart2f740782013-08-04 00:49:21 +1200672
673 private void deletePrefixFlows(Prefix prefix) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200674 if (!topologyReady) {
675 return;
676 }
677
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200678 log.debug("In deletePrefixFlows for {}", prefix);
Jonathan Hart2f740782013-08-04 00:49:21 +1200679
680 /*for (Map.Entry<Prefix, PushedFlowMod> entry : pushedFlows.entries()) {
681 log.debug("Pushed flow: {} => {}", entry.getKey(), entry.getValue());
682 }*/
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200683
684 Collection<PushedFlowMod> pushedFlowMods
Jonathan Hart2f740782013-08-04 00:49:21 +1200685 = pushedFlows.removeAll(prefix);
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200686
687 for (PushedFlowMod pfm : pushedFlowMods) {
688 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
689 new Object[] {HexString.toHexString(pfm.getDpid()),
690 pfm.getFlowMod().getMatch().getNetworkDestination() +
691 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
692 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
693 .getDataLayerAddress())});
694
695 OFFlowMod fm = pfm.getFlowMod();
696
697 fm.setCommand(OFFlowMod.OFPFC_DELETE)
Jonathan Hart2f740782013-08-04 00:49:21 +1200698 .setOutPort(OFPort.OFPP_NONE)
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200699 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
700
701 fm.getActions().clear();
702
703 IOFSwitch sw = floodlightProvider.getSwitches().get(pfm.getDpid());
704 if (sw == null) {
705 log.warn("Switch not found when pushing delete flow mod");
706 continue;
707 }
708
709 try {
710 sw.write(fm, null);
711 sw.flush();
712 } catch (IOException e) {
713 log.error("Failure writing flow mod", e);
714 }
715 }
716 }
717
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700718 /*
719 * On startup we need to calculate a full mesh of paths between all gateway
720 * switches
721 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200722 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700723 //For each border router, calculate and install a path from every other
724 //border switch to said border router. However, don't install the entry
725 //in to the first hop switch, as we need to install an entry to rewrite
726 //for each prefix received. This will be done later when prefixes have
727 //actually been received.
728
Jonathan Hartc824ad02013-07-03 15:58:45 +1200729 for (BgpPeer peer : bgpPeers.values()) {
730 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200731
732 //See if we know the MAC address of the peer. If not we can't
733 //do anything until we learn it
734 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
735 if (mac == null) {
736 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
737 //Put in the pending paths list first
738 pathsWaitingOnArp.put(peer.getIpAddress(),
739 new PathUpdate(peerInterface, peer.getIpAddress()));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700740
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200741 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
742 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700743 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200744
745 //If we know the MAC, lets go ahead and push the paths to this peer
746 calculateAndPushPath(peerInterface, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700747 }
748 }
749
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200750 private void calculateAndPushPath(Interface dstInterface, MACAddress dstMacAddress) {
751 for (Interface srcInterface : interfaces.values()) {
752 if (dstInterface.equals(srcInterface.getName())){
753 continue;
754 }
755
756 DataPath shortestPath = topoRouteService.getShortestPath(
757 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
758
759 if (shortestPath == null){
760 log.debug("Shortest path between {} and {} not found",
761 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
762 return; // just quit here?
763 }
764
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200765 installPath(shortestPath.flowEntries(), dstMacAddress);
766 }
767 }
768
769 private void installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700770 //Set up the flow mod
771 OFFlowMod fm =
772 (OFFlowMod) floodlightProvider.getOFMessageFactory()
773 .getMessage(OFType.FLOW_MOD);
774
775 OFActionOutput action = new OFActionOutput();
776 action.setMaxLength((short)0xffff);
777 List<OFAction> actions = new ArrayList<OFAction>();
778 actions.add(action);
779
780 fm.setIdleTimeout((short)0)
781 .setHardTimeout((short)0)
782 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
783 .setCookie(L2_FWD_COOKIE)
784 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700785 .setActions(actions)
786 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
787
788 //Don't push the first flow entry. We need to push entries in the
789 //first switch based on IP prefix which we don't know yet.
790 for (int i = 1; i < flowEntries.size(); i++){
791 FlowEntry flowEntry = flowEntries.get(i);
792
793 OFMatch match = new OFMatch();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200794 //TODO Again using MAC address from configuration
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200795 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700796 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
797 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
798
799 fm.setMatch(match);
800
801 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
802
803 if (sw == null){
804 log.warn("Switch not found when pushing flow mod");
805 continue;
806 }
807
808 List<OFMessage> msglist = new ArrayList<OFMessage>();
809 msglist.add(fm);
810 try {
811 sw.write(msglist, null);
812 sw.flush();
813 } catch (IOException e) {
814 log.error("Failure writing flow mod", e);
815 }
816
817 try {
818 fm = fm.clone();
819 } catch (CloneNotSupportedException e1) {
820 log.error("Failure cloning flow mod", e1);
821 }
822 }
823 }
824
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200825 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200826 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200827 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
828
829 DataPath path = topoRouteService.getShortestPath(
830 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
831
832 if (path == null){
833 log.debug("Unable to compute path for BGP traffic for {}",
834 bgpPeer.getIpAddress());
835 continue;
836 }
837
838 //Set up the flow mod
839 OFFlowMod fm =
840 (OFFlowMod) floodlightProvider.getOFMessageFactory()
841 .getMessage(OFType.FLOW_MOD);
842
843 OFActionOutput action = new OFActionOutput();
844 action.setMaxLength((short)0xffff);
845 List<OFAction> actions = new ArrayList<OFAction>();
846 actions.add(action);
847
848 fm.setIdleTimeout((short)0)
849 .setHardTimeout((short)0)
850 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
851 .setCookie(BGP_COOKIE)
852 .setCommand(OFFlowMod.OFPFC_ADD)
853 .setPriority(SDNIP_PRIORITY)
854 .setActions(actions)
855 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
856
857 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
858 OFMatch forwardMatchSrc = new OFMatch();
859
860
861 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
862 + "/32";
863 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
864 + "/32";
865
866 //Common match fields
867 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
868 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
869 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
870 forwardMatchSrc.setTransportDestination(BGP_PORT);
871 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
872 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
873
874
875 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
876
877 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
878 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
879
880 OFMatch forwardMatchDst = forwardMatchSrc.clone();
881
882 forwardMatchSrc.setTransportSource(BGP_PORT);
883 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
884 forwardMatchDst.setTransportDestination(BGP_PORT);
885 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
886
887 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
888 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
889
890 OFMatch reverseMatchDst = reverseMatchSrc.clone();
891
892 reverseMatchSrc.setTransportSource(BGP_PORT);
893 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
894 reverseMatchDst.setTransportDestination(BGP_PORT);
895 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
896
897 fm.setMatch(forwardMatchSrc);
898
899 for (FlowEntry flowEntry : path.flowEntries()){
900 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
901 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
902 try {
903 forwardFlowModSrc = fm.clone();
904 forwardFlowModDst = fm.clone();
905 reverseFlowModSrc = fm.clone();
906 reverseFlowModDst = fm.clone();
907 } catch (CloneNotSupportedException e) {
908 log.warn("Clone failed", e);
909 continue;
910 }
911
912 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
913 forwardFlowModSrc.setMatch(forwardMatchSrc);
914 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
915 .setPort(flowEntry.outPort().value());
916
917 forwardMatchDst.setInputPort(flowEntry.inPort().value());
918 forwardFlowModDst.setMatch(forwardMatchDst);
919 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
920 .setPort(flowEntry.outPort().value());
921
922 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
923 reverseFlowModSrc.setMatch(reverseMatchSrc);
924 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
925 .setPort(flowEntry.inPort().value());
926
927 reverseMatchDst.setInputPort(flowEntry.outPort().value());
928 reverseFlowModDst.setMatch(reverseMatchDst);
929 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
930 .setPort(flowEntry.inPort().value());
931
932 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
933
934 //Hopefully the switch is there
935 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
936 msgList.add(forwardFlowModSrc);
937 msgList.add(forwardFlowModDst);
938 msgList.add(reverseFlowModSrc);
939 msgList.add(reverseFlowModDst);
940
941 try {
942 sw.write(msgList, null);
943 sw.flush();
944 } catch (IOException e) {
945 log.error("Failure writing flow mod", e);
946 }
947 }
948 }
949 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200950
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200951 @Override
952 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
953 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
954 MACAddress.valueOf(macAddress).toString());
955
956 Set<PathUpdate> pathsToPush = pathsWaitingOnArp.removeAll(ipAddress);
957
958 for (PathUpdate update : pathsToPush) {
959 log.debug("Pushing path to {} at {} on {}", new Object[] {
960 update.getDstIpAddress().getHostAddress(),
961 MACAddress.valueOf(macAddress),
962 update.getDstInterface().getSwitchPort()});
963 calculateAndPushPath(update.getDstInterface(),
964 MACAddress.valueOf(macAddress));
965 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200966
967 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
968
969 for (RibUpdate update : prefixesToPush) {
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200970 //These will always be adds
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200971 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
972 update.getRibEntry().nextHop.getHostAddress());
Jonathan Hart2f740782013-08-04 00:49:21 +1200973 addPrefixFlows(update.getPrefix(), update.getRibEntry());
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200974 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200975 }
976
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200977 private void beginRouting(){
978 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200979 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200980 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200981
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200982 //Traverse ptree and create flows for all routes
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200983 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
984 if (node.rib != null){
985 prefixAdded(node);
986 }
987 }
988 }
989
990 private void checkSwitchesConnected(){
991 for (String dpid : switches){
992 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
993 log.debug("Not all switches are here yet");
994 return;
995 }
996 }
997 switchesConnected = true;
998 }
999
Jonathan Hartc824ad02013-07-03 15:58:45 +12001000 //Actually we only need to go half way round to verify full mesh connectivity
1001 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001002 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001003 for (Interface dstInterface : interfaces.values()) {
1004 for (Interface srcInterface : interfaces.values()) {
1005 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001006 continue;
1007 }
1008
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001009 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001010 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001011
1012 if (shortestPath == null){
1013 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001014 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001015 return;
1016 }
1017 }
1018 }
1019 topologyReady = true;
1020 }
1021
1022 private void checkStatus(){
1023 log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
1024
1025 if (!switchesConnected){
1026 checkSwitchesConnected();
1027 }
1028 boolean oldTopologyReadyStatus = topologyReady;
1029 if (switchesConnected && !topologyReady){
1030 checkTopologyReady();
1031 }
1032 if (!oldTopologyReadyStatus && topologyReady){
1033 beginRouting();
1034 }
1035 }
1036
pingping-lina2cbfad2013-03-07 08:39:21 +08001037 @Override
1038 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +08001039 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001040 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -07001041 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +08001042
Jonathan Hartc7ca35d2013-06-25 20:54:25 +12001043 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
1044
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001045 ExecutorService e = Executors.newSingleThreadExecutor(
1046 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
1047
1048
1049 e.execute(new Runnable() {
1050 @Override
1051 public void run() {
1052 doUpdatesThread();
1053 }
1054 });
1055
Jonathan Hart61ba9372013-05-19 20:10:29 -07001056 //Retrieve the RIB from BGPd during startup
1057 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +08001058 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001059
1060 private void doUpdatesThread() {
1061 boolean interrupted = false;
1062 try {
1063 while (true) {
1064 try {
1065 RibUpdate update = ribUpdates.take();
1066 switch (update.getOperation()){
1067 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001068 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001069 break;
1070 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001071 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001072 break;
1073 }
1074 } catch (InterruptedException e) {
1075 interrupted = true;
1076 }
1077 }
1078 } finally {
1079 if (interrupted) {
1080 Thread.currentThread().interrupt();
1081 }
1082 }
1083 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001084
1085 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001086 public void topologyChanged() {
1087 //There seems to be more topology events than there should be. Lots of link
1088 //updated, port up and switch updated on what should be a fairly static topology
pingping-lina2cbfad2013-03-07 08:39:21 +08001089
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001090 boolean refreshNeeded = false;
1091 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1092 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1093 //We don't need to recalculate anything for just link updates
1094 //They happen way too frequently (may be a bug in our link discovery)
1095 refreshNeeded = true;
1096 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001097
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001098 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001099
Jonathan Hart98957bf2013-07-01 14:49:24 +12001100 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1101 synchronized (linkUpdates) {
1102 linkUpdates.add(ldu);
1103 }
1104 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001105 }
1106
1107 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001108 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001109 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001110 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001111
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001112 //TODO determine whether we need to listen for switch joins
1113 @Override
1114 public void addedSwitch(IOFSwitch sw) {
1115 //checkStatus();
1116 }
1117
1118 @Override
1119 public void removedSwitch(IOFSwitch sw) {
1120 // TODO Auto-generated method stub
1121 }
1122
1123 @Override
1124 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001125
1126 @Override
1127 public String getName() {
1128 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +08001129 }
1130}