blob: 7ceb3f3dca22de63ce9d4a5904890f14099aff1a [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 HashMap<InetAddress, RibUpdate> prefixesWaitingOnArp;
130 //protected HashMap<InetAddress, PathUpdate> pathsWaitingOnArp;
131 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
132 protected SetMultimap<InetAddress, PathUpdate> pathsWaitingOnArp;
133
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200134 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
135
136 private class PushedFlowMod {
137 private long dpid;
138 private OFFlowMod flowMod;
139
140 public PushedFlowMod(long dpid, OFFlowMod flowMod) {
141 this.dpid = dpid;
142 this.flowMod = flowMod;
143 }
144
145 public long getDpid() {
146 return dpid;
147 }
148
149 public OFFlowMod getFlowMod() {
150 return flowMod;
151 }
152 }
153
Jonathan Hart98957bf2013-07-01 14:49:24 +1200154 protected class TopologyChangeDetector implements Runnable {
155 @Override
156 public void run() {
157 log.debug("Running topology change detection task");
158 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200159 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200160 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
161
162 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200163
164 Iterator<LDUpdate> it = linkUpdates.iterator();
165 while (it.hasNext()){
166 LDUpdate ldu = it.next();
167 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
168 ldu.getDst(), ldu.getDstPort());
169
170 if (activeLinks.contains(l)){
171 log.debug("Not found: {}", l);
172 it.remove();
173 }
174 }
175 }
176
177 if (linkUpdates.isEmpty()){
178 //All updates have been seen in network map.
179 //We can check if topology is ready
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200180 log.debug("No known changes outstanding. Checking topology now");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200181 checkStatus();
182 }
183 else {
184 //We know of some link updates that haven't propagated to the database yet
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200185 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200186 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
187 }
188 }
189 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700190
Jonathan Hartd1f23252013-06-13 15:17:05 +1200191 private void readGatewaysConfiguration(String gatewaysFilename){
192 File gatewaysFile = new File(gatewaysFilename);
193 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700194
Jonathan Hartd1f23252013-06-13 15:17:05 +1200195 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200196 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
197
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200198 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200199 interfaces = new HashMap<String, Interface>();
200 for (Interface intf : config.getInterfaces()){
201 interfaces.put(intf.getName(), intf);
202 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200203 bgpPeers = new HashMap<InetAddress, BgpPeer>();
204 for (BgpPeer peer : config.getPeers()){
205 bgpPeers.put(peer.getIpAddress(), peer);
206 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200207
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200208 bgpdAttachmentPoint = new SwitchPort(
209 new Dpid(config.getBgpdAttachmentDpid()),
210 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200211
Jonathan Hartd1f23252013-06-13 15:17:05 +1200212 } catch (JsonParseException e) {
213 log.error("Error in JSON file", e);
214 System.exit(1);
215 } catch (JsonMappingException e) {
216 log.error("Error in JSON file", e);
217 System.exit(1);
218 } catch (IOException e) {
219 log.error("Error reading JSON file", e);
220 System.exit(1);
221 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700222 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800223
224 @Override
225 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700226 Collection<Class<? extends IFloodlightService>> l
227 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800228 l.add(IBgpRouteService.class);
229 return l;
230 }
231
232 @Override
233 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700234 Map<Class<? extends IFloodlightService>, IFloodlightService> m
235 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800236 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800237 return m;
238 }
239
pingping-lina2cbfad2013-03-07 08:39:21 +0800240 @Override
241 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700242 Collection<Class<? extends IFloodlightService>> l
243 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800244 l.add(IFloodlightProviderService.class);
245 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700246 l.add(IDeviceService.class);
247 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800248 return l;
249 }
250
251 @Override
252 public void init(FloodlightModuleContext context)
253 throws FloodlightModuleException {
254
255 ptree = new Ptree(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200256
257 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200258
pingping-lina2cbfad2013-03-07 08:39:21 +0800259 // Register floodlight provider and REST handler.
260 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800261 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700262 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200263 restApi = context.getServiceImpl(IRestApiService.class);
264
265 //TODO We'll initialise this here for now, but it should really be done as
266 //part of the controller core
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200267 proxyArp = new ProxyArpManager(floodlightProvider, topology, devices);
pingping-lina2cbfad2013-03-07 08:39:21 +0800268
Jonathan Hart98957bf2013-07-01 14:49:24 +1200269 linkUpdates = new ArrayList<LDUpdate>();
270 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
271 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700272
273 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200274
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200275 pathsWaitingOnArp = Multimaps.synchronizedSetMultimap(
276 HashMultimap.<InetAddress, PathUpdate>create());
277 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
278 HashMultimap.<InetAddress, RibUpdate>create());
279
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200280 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
281
Jonathan Hart61ba9372013-05-19 20:10:29 -0700282 //Read in config values
283 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
284 if (bgpdRestIp == null){
285 log.error("BgpdRestIp property not found in config file");
286 System.exit(1);
287 }
288 else {
289 log.info("BgpdRestIp set to {}", bgpdRestIp);
290 }
291
292 routerId = context.getConfigParams(this).get("RouterId");
293 if (routerId == null){
294 log.error("RouterId property not found in config file");
295 System.exit(1);
296 }
297 else {
298 log.info("RouterId set to {}", routerId);
299 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200300
Jonathan Hart9575cb62013-07-05 13:43:49 +1200301 String configFilenameParameter = context.getConfigParams(this).get("configfile");
302 if (configFilenameParameter != null){
303 configFilename = configFilenameParameter;
304 }
305 log.debug("Config file set to {}", configFilename);
306
307 readGatewaysConfiguration(configFilename);
pingping-lina2cbfad2013-03-07 08:39:21 +0800308 // Test.
309 //test();
310 }
311
312 public Ptree getPtree() {
313 return ptree;
314 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700315
316 public void clearPtree() {
317 //ptree = null;
318 ptree = new Ptree(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800319 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700320
pingping-line2a09ca2013-03-23 09:33:58 +0800321 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700322 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800323 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700324
pingping-line2a09ca2013-03-23 09:33:58 +0800325 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700326 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800327 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800328
329 // Return nexthop address as byte array.
330 public Rib lookupRib(byte[] dest) {
331 if (ptree == null) {
332 log.debug("lookupRib: ptree null");
333 return null;
334 }
335
336 PtreeNode node = ptree.match(dest, 32);
337 if (node == null) {
338 log.debug("lookupRib: ptree node null");
339 return null;
340 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700341
pingping-lina2cbfad2013-03-07 08:39:21 +0800342 if (node.rib == null) {
343 log.debug("lookupRib: ptree rib null");
344 return null;
345 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700346
pingping-lina2cbfad2013-03-07 08:39:21 +0800347 ptree.delReference(node);
348
349 return node.rib;
350 }
351
Jonathan Hart61ba9372013-05-19 20:10:29 -0700352 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800353 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700354 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800355 System.out.println("Here it is");
356 Prefix p = new Prefix("128.0.0.0", 8);
357 Prefix q = new Prefix("8.0.0.0", 8);
358 Prefix r = new Prefix("10.0.0.0", 24);
359 Prefix a = new Prefix("10.0.0.1", 32);
360
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200361 ptree.acquire(p.getAddress(), p.getPrefixLength());
362 ptree.acquire(q.getAddress(), q.getPrefixLength());
363 ptree.acquire(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800364
365 System.out.println("Traverse start");
366 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
367 Prefix p_result = new Prefix(node.key, node.keyBits);
368 }
369
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200370 PtreeNode n = ptree.match(a.getAddress(), a.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800371 if (n != null) {
372 System.out.println("Matched prefix for 10.0.0.1:");
373 Prefix x = new Prefix(n.key, n.keyBits);
374 ptree.delReference(n);
375 }
376
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200377 n = ptree.lookup(p.getAddress(), p.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800378 if (n != null) {
379 ptree.delReference(n);
380 ptree.delReference(n);
381 }
382 System.out.println("Traverse start");
383 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
384 Prefix p_result = new Prefix(node.key, node.keyBits);
385 }
386
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200387 n = ptree.lookup(q.getAddress(), q.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800388 if (n != null) {
389 ptree.delReference(n);
390 ptree.delReference(n);
391 }
392 System.out.println("Traverse start");
393 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
394 Prefix p_result = new Prefix(node.key, node.keyBits);
395 }
396
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200397 n = ptree.lookup(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800398 if (n != null) {
399 ptree.delReference(n);
400 ptree.delReference(n);
401 }
402 System.out.println("Traverse start");
403 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
404 Prefix p_result = new Prefix(node.key, node.keyBits);
405 }
406
407 }
408
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200409 private String getPrefixFromPtree(PtreeNode node){
410 InetAddress address = null;
411 try {
412 address = InetAddress.getByAddress(node.key);
413 } catch (UnknownHostException e1) {
414 //Should never happen is the reverse conversion has already been done
415 log.error("Malformed IP address");
416 return "";
417 }
418 return address.toString() + "/" + node.rib.masklen;
419 }
420
Jonathan Hart61ba9372013-05-19 20:10:29 -0700421 private void retrieveRib(){
422 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
423 String response = RestClient.get(url);
424
425 if (response.equals("")){
426 return;
427 }
428
429 response = response.replaceAll("\"", "'");
430 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
431 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
432 String router_id = jsonObj.getString("router-id");
433
434 int size = rib_json_array.size();
435
436 log.info("Retrived RIB of {} entries from BGPd", size);
437
438 for (int j = 0; j < size; j++) {
439 JSONObject second_json_object = rib_json_array.getJSONObject(j);
440 String prefix = second_json_object.getString("prefix");
441 String nexthop = second_json_object.getString("nexthop");
442
443 //insert each rib entry into the local rib;
444 String[] substring = prefix.split("/");
445 String prefix1 = substring[0];
446 String mask1 = substring[1];
447
448 Prefix p;
449 try {
450 p = new Prefix(prefix1, Integer.valueOf(mask1));
451 } catch (NumberFormatException e) {
452 log.warn("Wrong mask format in RIB JSON: {}", mask1);
453 continue;
454 } catch (UnknownHostException e1) {
455 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
456 continue;
457 }
458
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200459 PtreeNode node = ptree.acquire(p.getAddress(), p.getPrefixLength());
460 Rib rib = new Rib(router_id, nexthop, p.getPrefixLength());
Jonathan Hart61ba9372013-05-19 20:10:29 -0700461
462 if (node.rib != null) {
463 node.rib = null;
464 ptree.delReference(node);
465 }
466
467 node.rib = rib;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700468
Jonathan Hart2f740782013-08-04 00:49:21 +1200469 //prefixAdded(node);
470 addPrefixFlows(p, rib);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700471 }
472 }
473
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200474 @Override
475 public void newRibUpdate(RibUpdate update) {
476 ribUpdates.add(update);
477 }
478
Jonathan Hart2f740782013-08-04 00:49:21 +1200479 public void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200480 Prefix prefix = update.getPrefix();
481
482 PtreeNode node = ptree.acquire(prefix.getAddress(), prefix.getPrefixLength());
483
484 if (node.rib != null) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200485 //There was an existing nexthop for this prefix. This update supersedes that,
486 //so we need to remove the old flows for this prefix from the switches
487 deletePrefixFlows(prefix);
488
489 //Then remove the old nexthop from the Ptree
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200490 node.rib = null;
491 ptree.delReference(node);
492 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200493
494 //Put the new nexthop in the Ptree
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200495 node.rib = update.getRibEntry();
496
Jonathan Hart2f740782013-08-04 00:49:21 +1200497 //Push flows for the new <prefix, nexthop>
498 //prefixAdded(node);
499 addPrefixFlows(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200500 }
501
Jonathan Hart2f740782013-08-04 00:49:21 +1200502 public void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200503 Prefix prefix = update.getPrefix();
504
505 PtreeNode node = ptree.lookup(prefix.getAddress(), prefix.getPrefixLength());
506
507 /*
508 * Remove the flows from the switches before the rib is lost
509 * Theory: we could get a delete for a prefix not in the Ptree.
510 * This would result in a null node being returned. We could get a delete for
511 * a node that's not actually there, but is a aggregate node. This would result
512 * in a non-null node with a null rib. Only a non-null node with a non-null
513 * rib is an actual prefix in the Ptree.
514 */
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200515 //if (node != null && node.rib != null){
516 //prefixDeleted(node);
517 //}
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200518
519 if (node != null && node.rib != null) {
520 if (update.getRibEntry().equals(node.rib)) {
521 node.rib = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200522 ptree.delReference(node);
523
Jonathan Hart2f740782013-08-04 00:49:21 +1200524 //prefixDeleted(update);
525 deletePrefixFlows(update.getPrefix());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200526 }
527 }
528 }
529
Jonathan Hart2f740782013-08-04 00:49:21 +1200530 //TODO compatibility layer, used by beginRouting()
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200531 public void prefixAdded(PtreeNode node) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200532 //String strPrefix = getPrefixFromPtree(node);
533
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200534 Prefix prefix = null;
535 try {
536 prefix = new Prefix(node.key, node.rib.masklen);
537 } catch (UnknownHostException e) {
538 log.error(" ", e);
539 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200540
Jonathan Hart2f740782013-08-04 00:49:21 +1200541 //RibUpdate update = new RibUpdate(Operation.UPDATE, prefix, node.rib);
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200542
Jonathan Hart2f740782013-08-04 00:49:21 +1200543 //addPrefixFlows(update);
544
545 addPrefixFlows(prefix, node.rib);
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200546 }
547
Jonathan Hart2f740782013-08-04 00:49:21 +1200548 //private void addPrefixFlows(RibUpdate update) {
549 private void addPrefixFlows(Prefix prefix, Rib rib) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200550 if (!topologyReady){
551 return;
552 }
553
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200554 //TODO before we do anything, we have to check that the RIB entry is still in the
555 //Ptree because it could have been removed while we were waiting for ARP.
556 //I think we'll have to make prefixAdded and prefixDelete atomic as well
557 //to protect against the prefix getting deleted while where trying to add it
Jonathan Hart2f740782013-08-04 00:49:21 +1200558
Jonathan Hartc824ad02013-07-03 15:58:45 +1200559 log.debug("New prefix {} added, next hop {}, routerId {}",
Jonathan Hart2f740782013-08-04 00:49:21 +1200560 //new Object[] {update.getPrefix(), update.getRibEntry().nextHop.getHostAddress(),
561 //update.getRibEntry().routerId.getHostAddress()});
562 new Object[] {prefix, rib.nextHop.getHostAddress(),
563 rib.routerId.getHostAddress()});
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200564
Jonathan Hartc824ad02013-07-03 15:58:45 +1200565 //TODO this is wrong, we shouldn't be dealing with BGP peers here.
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200566 //We need to figure out where the device is attached and what its
Jonathan Hartc824ad02013-07-03 15:58:45 +1200567 //mac address is by learning.
568 //The next hop is not necessarily the peer, and the peer's attachment
569 //point is not necessarily the next hop's attachment point.
Jonathan Hart2f740782013-08-04 00:49:21 +1200570 //BgpPeer peer = bgpPeers.get(update.getRibEntry().nextHop);
571 BgpPeer peer = bgpPeers.get(rib.nextHop);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700572
Jonathan Hartc824ad02013-07-03 15:58:45 +1200573 if (peer == null){
574 //TODO local router isn't in peers list so this will get thrown
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200575 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
Jonathan Hartc824ad02013-07-03 15:58:45 +1200576
577 //The other scenario is this is a route server route. In that
578 //case the next hop is not in our configuration
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200579 log.error("Couldn't find next hop router in router {} in config",
Jonathan Hart2f740782013-08-04 00:49:21 +1200580 //update.getRibEntry().nextHop.getHostAddress());
581 rib.nextHop.getHostAddress());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700582 return; //just quit out here? This is probably a configuration error
583 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200584
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200585 //Get MAC address for peer from the ARP module
586 //TODO separate out the 'ask for MAC' bit to another method
587 byte[] peerMacAddress = proxyArp.getMacAddress(peer.getIpAddress());
588 if (peerMacAddress == null) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200589 //A RibUpdate is still a nice way to package them up
590 prefixesWaitingOnArp.put(peer.getIpAddress(),
591 new RibUpdate(Operation.UPDATE, prefix, rib));
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200592 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
593 return;
594 }
595
Jonathan Hartc824ad02013-07-03 15:58:45 +1200596 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200597
Jonathan Hartc824ad02013-07-03 15:58:45 +1200598 //Add a flow to rewrite mac for this prefix to all border switches
599 for (Interface srcInterface : interfaces.values()) {
600 if (srcInterface == peerInterface) {
601 //Don't push a flow for the switch where this peer is attached
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700602 continue;
603 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200604
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700605 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200606 srcInterface.getSwitchPort(),
607 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700608
609 if (shortestPath == null){
610 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200611 srcInterface.getSwitchPort(),
612 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700613 return; // just quit here?
614 }
615
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700616 //Set up the flow mod
617 OFFlowMod fm =
618 (OFFlowMod) floodlightProvider.getOFMessageFactory()
619 .getMessage(OFType.FLOW_MOD);
620
621 fm.setIdleTimeout((short)0)
622 .setHardTimeout((short)0)
623 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
624 .setCookie(MAC_RW_COOKIE)
625 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200626 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700627 .setLengthU(OFFlowMod.MINIMUM_LENGTH
628 + OFActionDataLayerDestination.MINIMUM_LENGTH
629 + OFActionOutput.MINIMUM_LENGTH);
630
631 OFMatch match = new OFMatch();
632 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200633 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700634
Jonathan Hartc824ad02013-07-03 15:58:45 +1200635 //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
636 //match.setDataLayerSource(peer.getMacAddress().toBytes());
637 //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200638
639 InetAddress address = null;
640 try {
Jonathan Hart2f740782013-08-04 00:49:21 +1200641 //address = InetAddress.getByAddress(update.getPrefix().getAddress());
642 address = InetAddress.getByAddress(prefix.getAddress());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200643 } catch (UnknownHostException e1) {
644 //Should never happen is the reverse conversion has already been done
645 log.error("Malformed IP address");
646 return;
647 }
648
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200649 //match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
650 match.setFromCIDR(address.getHostAddress() + "/" +
Jonathan Hart2f740782013-08-04 00:49:21 +1200651 //update.getPrefix().getPrefixLength(), OFMatch.STR_NW_DST);
652 prefix.getPrefixLength(), OFMatch.STR_NW_DST);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200653 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700654
655 //Set up MAC rewrite action
656 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200657 //TODO the peer's mac address is not necessarily the next hop's...
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200658 //macRewriteAction.setDataLayerAddress(peer.getMacAddress().toBytes());
659 macRewriteAction.setDataLayerAddress(peerMacAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700660
661 //Set up output action
662 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200663 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700664
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200665 Port outputPort = shortestPath.flowEntries().get(0).outPort();
666 outputAction.setPort(outputPort.value());
667
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700668 List<OFAction> actions = new ArrayList<OFAction>();
669 actions.add(macRewriteAction);
670 actions.add(outputAction);
671 fm.setActions(actions);
672
673 //Write to switch
674 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200675 .get(srcInterface.getDpid());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700676
677 if (sw == null){
678 log.warn("Switch not found when pushing flow mod");
679 continue;
680 }
681
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200682 //TODO if prefix Added/Deleted are synchronized this shouldn't have to be
Jonathan Hart2f740782013-08-04 00:49:21 +1200683 //pushedFlows.put(update.getPrefix(), new PushedFlowMod(sw.getId(), fm));
684 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200685
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700686 List<OFMessage> msglist = new ArrayList<OFMessage>();
687 msglist.add(fm);
688 try {
689 sw.write(msglist, null);
690 sw.flush();
691 } catch (IOException e) {
692 log.error("Failure writing flow mod", e);
693 }
694 }
695 }
696
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200697 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200698 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200699
Jonathan Hart2f740782013-08-04 00:49:21 +1200700 /*
701 private void prefixDeleted(RibUpdate update) {
702 deletePrefix(update.getPrefix());
703 }
704 */
705
706 private void deletePrefixFlows(Prefix prefix) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200707 if (!topologyReady) {
708 return;
709 }
710
Jonathan Hart2f740782013-08-04 00:49:21 +1200711 //log.debug("In prefixDeleted for {}", update.getPrefix());
712 log.debug("In prefixDeleted for {}", prefix);
713
714 /*for (Map.Entry<Prefix, PushedFlowMod> entry : pushedFlows.entries()) {
715 log.debug("Pushed flow: {} => {}", entry.getKey(), entry.getValue());
716 }*/
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200717
718 Collection<PushedFlowMod> pushedFlowMods
Jonathan Hart2f740782013-08-04 00:49:21 +1200719 //= pushedFlows.removeAll(update.getPrefix());
720 = pushedFlows.removeAll(prefix);
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200721
722 for (PushedFlowMod pfm : pushedFlowMods) {
723 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
724 new Object[] {HexString.toHexString(pfm.getDpid()),
725 pfm.getFlowMod().getMatch().getNetworkDestination() +
726 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
727 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
728 .getDataLayerAddress())});
729
730 OFFlowMod fm = pfm.getFlowMod();
731
732 fm.setCommand(OFFlowMod.OFPFC_DELETE)
Jonathan Hart2f740782013-08-04 00:49:21 +1200733 .setOutPort(OFPort.OFPP_NONE)
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200734 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
735
736 fm.getActions().clear();
737
738 IOFSwitch sw = floodlightProvider.getSwitches().get(pfm.getDpid());
739 if (sw == null) {
740 log.warn("Switch not found when pushing delete flow mod");
741 continue;
742 }
743
744 try {
745 sw.write(fm, null);
746 sw.flush();
747 } catch (IOException e) {
748 log.error("Failure writing flow mod", e);
749 }
750 }
751 }
752
753 /*public void prefixDeleted(PtreeNode node) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200754 if (!topologyReady) {
755 return;
756 }
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200757
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200758 String prefix = getPrefixFromPtree(node);
759
760 log.debug("Prefix {} deleted, next hop {}",
761 prefix, node.rib.nextHop.toString());
762
763 //Remove MAC rewriting flows from other border switches
Jonathan Hartc824ad02013-07-03 15:58:45 +1200764 BgpPeer peer = bgpPeers.get(node.rib.nextHop);
765 if (peer == null){
766 //either a router server route or local route. Can't handle right now
767 return;
768 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200769
Jonathan Hartc824ad02013-07-03 15:58:45 +1200770 Interface peerInterface = interfaces.get(peer.getInterfaceName());
771
772 for (Interface srcInterface : interfaces.values()) {
773 if (srcInterface == peerInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200774 continue;
775 }
776
777 //Set up the flow mod
778 OFFlowMod fm =
779 (OFFlowMod) floodlightProvider.getOFMessageFactory()
780 .getMessage(OFType.FLOW_MOD);
781
782 fm.setIdleTimeout((short)0)
783 .setHardTimeout((short)0)
784 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
785 .setCookie(MAC_RW_COOKIE)
786 .setCommand(OFFlowMod.OFPFC_DELETE)
Jonathan Hart9575cb62013-07-05 13:43:49 +1200787 .setOutPort(OFPort.OFPP_NONE)
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200788 .setPriority(SDNIP_PRIORITY)
789 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
790 //+ OFActionDataLayerDestination.MINIMUM_LENGTH
791 //+ OFActionOutput.MINIMUM_LENGTH);
792
793 OFMatch match = new OFMatch();
794 match.setDataLayerType(Ethernet.TYPE_IPv4);
795 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
796
Jonathan Hartc824ad02013-07-03 15:58:45 +1200797 //match.setDataLayerSource(ingressRouter.getRouterMac().toBytes());
798 //match.setDataLayerSource(peer.getMacAddress().toBytes());
799 //match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200800
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200801 InetAddress address = null;
802 try {
803 address = InetAddress.getByAddress(node.key);
804 } catch (UnknownHostException e1) {
805 //Should never happen is the reverse conversion has already been done
806 log.error("Malformed IP address");
807 return;
808 }
809
810 match.setFromCIDR(address.getHostAddress() + "/" + node.rib.masklen, OFMatch.STR_NW_DST);
811 fm.setMatch(match);
812
813 //Write to switch
814 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200815 .get(srcInterface.getDpid());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200816
817 if (sw == null){
818 log.warn("Switch not found when pushing flow mod");
819 continue;
820 }
821
822 List<OFMessage> msglist = new ArrayList<OFMessage>();
823 msglist.add(fm);
824 try {
825 sw.write(msglist, null);
826 sw.flush();
827 } catch (IOException e) {
828 log.error("Failure writing flow mod", e);
829 }
830 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200831 }*/
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700832
833 /*
834 * On startup we need to calculate a full mesh of paths between all gateway
835 * switches
836 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200837 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700838 //For each border router, calculate and install a path from every other
839 //border switch to said border router. However, don't install the entry
840 //in to the first hop switch, as we need to install an entry to rewrite
841 //for each prefix received. This will be done later when prefixes have
842 //actually been received.
843
Jonathan Hartc824ad02013-07-03 15:58:45 +1200844 for (BgpPeer peer : bgpPeers.values()) {
845 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200846
847 //See if we know the MAC address of the peer. If not we can't
848 //do anything until we learn it
849 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
850 if (mac == null) {
851 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
852 //Put in the pending paths list first
853 pathsWaitingOnArp.put(peer.getIpAddress(),
854 new PathUpdate(peerInterface, peer.getIpAddress()));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700855
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200856 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
857 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700858 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200859
860 //If we know the MAC, lets go ahead and push the paths to this peer
861 calculateAndPushPath(peerInterface, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700862 }
863 }
864
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200865 private void calculateAndPushPath(Interface dstInterface, MACAddress dstMacAddress) {
866 for (Interface srcInterface : interfaces.values()) {
867 if (dstInterface.equals(srcInterface.getName())){
868 continue;
869 }
870
871 DataPath shortestPath = topoRouteService.getShortestPath(
872 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
873
874 if (shortestPath == null){
875 log.debug("Shortest path between {} and {} not found",
876 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
877 return; // just quit here?
878 }
879
880 //install flows
881 installPath(shortestPath.flowEntries(), dstMacAddress);
882 }
883 }
884
885 private void installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700886 //Set up the flow mod
887 OFFlowMod fm =
888 (OFFlowMod) floodlightProvider.getOFMessageFactory()
889 .getMessage(OFType.FLOW_MOD);
890
891 OFActionOutput action = new OFActionOutput();
892 action.setMaxLength((short)0xffff);
893 List<OFAction> actions = new ArrayList<OFAction>();
894 actions.add(action);
895
896 fm.setIdleTimeout((short)0)
897 .setHardTimeout((short)0)
898 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
899 .setCookie(L2_FWD_COOKIE)
900 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700901 .setActions(actions)
902 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
903
904 //Don't push the first flow entry. We need to push entries in the
905 //first switch based on IP prefix which we don't know yet.
906 for (int i = 1; i < flowEntries.size(); i++){
907 FlowEntry flowEntry = flowEntries.get(i);
908
909 OFMatch match = new OFMatch();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200910 //TODO Again using MAC address from configuration
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200911 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700912 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
913 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
914
915 fm.setMatch(match);
916
917 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
918
919 if (sw == null){
920 log.warn("Switch not found when pushing flow mod");
921 continue;
922 }
923
924 List<OFMessage> msglist = new ArrayList<OFMessage>();
925 msglist.add(fm);
926 try {
927 sw.write(msglist, null);
928 sw.flush();
929 } catch (IOException e) {
930 log.error("Failure writing flow mod", e);
931 }
932
933 try {
934 fm = fm.clone();
935 } catch (CloneNotSupportedException e1) {
936 log.error("Failure cloning flow mod", e1);
937 }
938 }
939 }
940
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200941 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200942 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200943 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
944
945 DataPath path = topoRouteService.getShortestPath(
946 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
947
948 if (path == null){
949 log.debug("Unable to compute path for BGP traffic for {}",
950 bgpPeer.getIpAddress());
951 continue;
952 }
953
954 //Set up the flow mod
955 OFFlowMod fm =
956 (OFFlowMod) floodlightProvider.getOFMessageFactory()
957 .getMessage(OFType.FLOW_MOD);
958
959 OFActionOutput action = new OFActionOutput();
960 action.setMaxLength((short)0xffff);
961 List<OFAction> actions = new ArrayList<OFAction>();
962 actions.add(action);
963
964 fm.setIdleTimeout((short)0)
965 .setHardTimeout((short)0)
966 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
967 .setCookie(BGP_COOKIE)
968 .setCommand(OFFlowMod.OFPFC_ADD)
969 .setPriority(SDNIP_PRIORITY)
970 .setActions(actions)
971 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
972
973 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
974 OFMatch forwardMatchSrc = new OFMatch();
975
976
977 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
978 + "/32";
979 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
980 + "/32";
981
982 //Common match fields
983 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
984 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
985 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
986 forwardMatchSrc.setTransportDestination(BGP_PORT);
987 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
988 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
989
990
991 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
992
993 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
994 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
995
996 OFMatch forwardMatchDst = forwardMatchSrc.clone();
997
998 forwardMatchSrc.setTransportSource(BGP_PORT);
999 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1000 forwardMatchDst.setTransportDestination(BGP_PORT);
1001 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
1002
1003 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
1004 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
1005
1006 OFMatch reverseMatchDst = reverseMatchSrc.clone();
1007
1008 reverseMatchSrc.setTransportSource(BGP_PORT);
1009 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1010 reverseMatchDst.setTransportDestination(BGP_PORT);
1011 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
1012
1013 fm.setMatch(forwardMatchSrc);
1014
1015 for (FlowEntry flowEntry : path.flowEntries()){
1016 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
1017 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
1018 try {
1019 forwardFlowModSrc = fm.clone();
1020 forwardFlowModDst = fm.clone();
1021 reverseFlowModSrc = fm.clone();
1022 reverseFlowModDst = fm.clone();
1023 } catch (CloneNotSupportedException e) {
1024 log.warn("Clone failed", e);
1025 continue;
1026 }
1027
1028 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
1029 forwardFlowModSrc.setMatch(forwardMatchSrc);
1030 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
1031 .setPort(flowEntry.outPort().value());
1032
1033 forwardMatchDst.setInputPort(flowEntry.inPort().value());
1034 forwardFlowModDst.setMatch(forwardMatchDst);
1035 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
1036 .setPort(flowEntry.outPort().value());
1037
1038 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
1039 reverseFlowModSrc.setMatch(reverseMatchSrc);
1040 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
1041 .setPort(flowEntry.inPort().value());
1042
1043 reverseMatchDst.setInputPort(flowEntry.outPort().value());
1044 reverseFlowModDst.setMatch(reverseMatchDst);
1045 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
1046 .setPort(flowEntry.inPort().value());
1047
1048 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
1049
1050 //Hopefully the switch is there
1051 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
1052 msgList.add(forwardFlowModSrc);
1053 msgList.add(forwardFlowModDst);
1054 msgList.add(reverseFlowModSrc);
1055 msgList.add(reverseFlowModDst);
1056
1057 try {
1058 sw.write(msgList, null);
1059 sw.flush();
1060 } catch (IOException e) {
1061 log.error("Failure writing flow mod", e);
1062 }
1063 }
1064 }
1065 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001066
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001067 @Override
1068 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
1069 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
1070 MACAddress.valueOf(macAddress).toString());
1071
1072 Set<PathUpdate> pathsToPush = pathsWaitingOnArp.removeAll(ipAddress);
1073
1074 for (PathUpdate update : pathsToPush) {
1075 log.debug("Pushing path to {} at {} on {}", new Object[] {
1076 update.getDstIpAddress().getHostAddress(),
1077 MACAddress.valueOf(macAddress),
1078 update.getDstInterface().getSwitchPort()});
1079 calculateAndPushPath(update.getDstInterface(),
1080 MACAddress.valueOf(macAddress));
1081 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001082
1083 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
1084
1085 for (RibUpdate update : prefixesToPush) {
1086 //These must always be adds
1087 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1088 update.getRibEntry().nextHop.getHostAddress());
Jonathan Hart2f740782013-08-04 00:49:21 +12001089 addPrefixFlows(update.getPrefix(), update.getRibEntry());
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001090 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001091 }
1092
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001093 private void beginRouting(){
1094 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001095 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001096 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001097
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001098 //Traverse ptree and create flows for all routes
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001099 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
1100 if (node.rib != null){
1101 prefixAdded(node);
1102 }
1103 }
1104 }
1105
1106 private void checkSwitchesConnected(){
1107 for (String dpid : switches){
1108 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1109 log.debug("Not all switches are here yet");
1110 return;
1111 }
1112 }
1113 switchesConnected = true;
1114 }
1115
Jonathan Hartc824ad02013-07-03 15:58:45 +12001116 //Actually we only need to go half way round to verify full mesh connectivity
1117 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001118 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001119 for (Interface dstInterface : interfaces.values()) {
1120 for (Interface srcInterface : interfaces.values()) {
1121 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001122 continue;
1123 }
1124
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001125 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001126 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001127
1128 if (shortestPath == null){
1129 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001130 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001131 return;
1132 }
1133 }
1134 }
1135 topologyReady = true;
1136 }
1137
1138 private void checkStatus(){
1139 log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
1140
1141 if (!switchesConnected){
1142 checkSwitchesConnected();
1143 }
1144 boolean oldTopologyReadyStatus = topologyReady;
1145 if (switchesConnected && !topologyReady){
1146 checkTopologyReady();
1147 }
1148 if (!oldTopologyReadyStatus && topologyReady){
1149 beginRouting();
1150 }
1151 }
1152
pingping-lina2cbfad2013-03-07 08:39:21 +08001153 @Override
1154 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +08001155 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001156 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -07001157 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +08001158
Jonathan Hartc7ca35d2013-06-25 20:54:25 +12001159 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
1160
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001161 ExecutorService e = Executors.newSingleThreadExecutor(
1162 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
1163
1164
1165 e.execute(new Runnable() {
1166 @Override
1167 public void run() {
1168 doUpdatesThread();
1169 }
1170 });
1171
Jonathan Hart61ba9372013-05-19 20:10:29 -07001172 //Retrieve the RIB from BGPd during startup
1173 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +08001174 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001175
1176 private void doUpdatesThread() {
1177 boolean interrupted = false;
1178 try {
1179 while (true) {
1180 try {
1181 RibUpdate update = ribUpdates.take();
1182 switch (update.getOperation()){
1183 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001184 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001185 break;
1186 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001187 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001188 break;
1189 }
1190 } catch (InterruptedException e) {
1191 interrupted = true;
1192 }
1193 }
1194 } finally {
1195 if (interrupted) {
1196 Thread.currentThread().interrupt();
1197 }
1198 }
1199 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001200
1201 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001202 public void topologyChanged() {
1203 //There seems to be more topology events than there should be. Lots of link
1204 //updated, port up and switch updated on what should be a fairly static topology
pingping-lina2cbfad2013-03-07 08:39:21 +08001205
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001206 boolean refreshNeeded = false;
1207 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1208 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1209 //We don't need to recalculate anything for just link updates
1210 //They happen way too frequently (may be a bug in our link discovery)
1211 refreshNeeded = true;
1212 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001213
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001214 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001215
Jonathan Hart98957bf2013-07-01 14:49:24 +12001216 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1217 synchronized (linkUpdates) {
1218 linkUpdates.add(ldu);
1219 }
1220 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001221 }
1222
1223 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001224 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001225 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001226 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001227
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001228 //TODO determine whether we need to listen for switch joins
1229 @Override
1230 public void addedSwitch(IOFSwitch sw) {
1231 //checkStatus();
1232 }
1233
1234 @Override
1235 public void removedSwitch(IOFSwitch sw) {
1236 // TODO Auto-generated method stub
1237 }
1238
1239 @Override
1240 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001241
1242 @Override
1243 public String getName() {
1244 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +08001245 }
1246}