blob: 9123792d66305e119f48cfe0ec0a29611bf4e21e [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
Jonathan Hartd7e158d2013-08-07 23:04:48 +120091 //protected static Ptree ptree;
92 protected IPatriciaTrie ptree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120093 protected BlockingQueue<RibUpdate> ribUpdates;
94
Jonathan Hart61ba9372013-05-19 20:10:29 -070095 protected String bgpdRestIp;
96 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120097 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070098
99 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
100 //the controller/OS should hand out cookie IDs to prevent conflicts.
101 protected final long APP_COOKIE = 0xa0000000000000L;
102 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
103 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
104 //Cookie for flows in ingress switches that rewrite the MAC address
105 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200106 //Cookie for flows that setup BGP paths
107 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200108 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
109 //need to be higher priority than this otherwise the rewrite may not get done
110 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700111
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200112 protected final short BGP_PORT = 179;
113
Jonathan Hart98957bf2013-07-01 14:49:24 +1200114 protected final int TOPO_DETECTION_WAIT = 2; //seconds
115
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200116 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200117 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200118 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200119 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200120 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200121
122 //True when all switches have connected
123 protected volatile boolean switchesConnected = false;
124 //True when we have a full mesh of shortest paths between gateways
125 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200126
Jonathan Hart98957bf2013-07-01 14:49:24 +1200127 protected ArrayList<LDUpdate> linkUpdates;
128 protected SingletonTask topologyChangeDetectorTask;
129
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200130 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
131 protected SetMultimap<InetAddress, PathUpdate> pathsWaitingOnArp;
132
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200133 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
134
135 private class PushedFlowMod {
136 private long dpid;
137 private OFFlowMod flowMod;
138
139 public PushedFlowMod(long dpid, OFFlowMod flowMod) {
140 this.dpid = dpid;
141 this.flowMod = flowMod;
142 }
143
144 public long getDpid() {
145 return dpid;
146 }
147
148 public OFFlowMod getFlowMod() {
149 return flowMod;
150 }
151 }
152
Jonathan Hart98957bf2013-07-01 14:49:24 +1200153 protected class TopologyChangeDetector implements Runnable {
154 @Override
155 public void run() {
156 log.debug("Running topology change detection task");
157 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200158 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200159 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
160
161 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200162
163 Iterator<LDUpdate> it = linkUpdates.iterator();
164 while (it.hasNext()){
165 LDUpdate ldu = it.next();
166 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
167 ldu.getDst(), ldu.getDstPort());
168
169 if (activeLinks.contains(l)){
170 log.debug("Not found: {}", l);
171 it.remove();
172 }
173 }
174 }
175
176 if (linkUpdates.isEmpty()){
177 //All updates have been seen in network map.
178 //We can check if topology is ready
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200179 log.debug("No known changes outstanding. Checking topology now");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200180 checkStatus();
181 }
182 else {
183 //We know of some link updates that haven't propagated to the database yet
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200184 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200185 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
186 }
187 }
188 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700189
Jonathan Hartd1f23252013-06-13 15:17:05 +1200190 private void readGatewaysConfiguration(String gatewaysFilename){
191 File gatewaysFile = new File(gatewaysFilename);
192 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700193
Jonathan Hartd1f23252013-06-13 15:17:05 +1200194 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200195 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
196
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200197 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200198 interfaces = new HashMap<String, Interface>();
199 for (Interface intf : config.getInterfaces()){
200 interfaces.put(intf.getName(), intf);
201 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200202 bgpPeers = new HashMap<InetAddress, BgpPeer>();
203 for (BgpPeer peer : config.getPeers()){
204 bgpPeers.put(peer.getIpAddress(), peer);
205 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200206
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200207 bgpdAttachmentPoint = new SwitchPort(
208 new Dpid(config.getBgpdAttachmentDpid()),
209 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200210
Jonathan Hartd1f23252013-06-13 15:17:05 +1200211 } catch (JsonParseException e) {
212 log.error("Error in JSON file", e);
213 System.exit(1);
214 } catch (JsonMappingException e) {
215 log.error("Error in JSON file", e);
216 System.exit(1);
217 } catch (IOException e) {
218 log.error("Error reading JSON file", e);
219 System.exit(1);
220 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700221 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800222
223 @Override
224 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700225 Collection<Class<? extends IFloodlightService>> l
226 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800227 l.add(IBgpRouteService.class);
228 return l;
229 }
230
231 @Override
232 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700233 Map<Class<? extends IFloodlightService>, IFloodlightService> m
234 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800235 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800236 return m;
237 }
238
pingping-lina2cbfad2013-03-07 08:39:21 +0800239 @Override
240 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700241 Collection<Class<? extends IFloodlightService>> l
242 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800243 l.add(IFloodlightProviderService.class);
244 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700245 l.add(IDeviceService.class);
246 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800247 return l;
248 }
249
250 @Override
251 public void init(FloodlightModuleContext context)
252 throws FloodlightModuleException {
253
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200254 //ptree = new Ptree(32);
255 ptree = new PatriciaTrie(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
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200312 //public Ptree getPtree() {
313 public IPatriciaTrie getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800314 return ptree;
315 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700316
317 public void clearPtree() {
318 //ptree = null;
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200319 //ptree = new Ptree(32);
320 ptree = new PatriciaTrie(32);
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 getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700324 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800325 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700326
pingping-line2a09ca2013-03-23 09:33:58 +0800327 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700328 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800329 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800330
331 // Return nexthop address as byte array.
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200332 /*
pingping-lina2cbfad2013-03-07 08:39:21 +0800333 public Rib lookupRib(byte[] dest) {
334 if (ptree == null) {
335 log.debug("lookupRib: ptree null");
336 return null;
337 }
338
339 PtreeNode node = ptree.match(dest, 32);
340 if (node == null) {
341 log.debug("lookupRib: ptree node null");
342 return null;
343 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700344
pingping-lina2cbfad2013-03-07 08:39:21 +0800345 if (node.rib == null) {
346 log.debug("lookupRib: ptree rib null");
347 return null;
348 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700349
pingping-lina2cbfad2013-03-07 08:39:21 +0800350 ptree.delReference(node);
351
352 return node.rib;
353 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200354 */
pingping-lina2cbfad2013-03-07 08:39:21 +0800355
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200356 /*
Jonathan Hart61ba9372013-05-19 20:10:29 -0700357 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800358 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700359 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800360 System.out.println("Here it is");
361 Prefix p = new Prefix("128.0.0.0", 8);
362 Prefix q = new Prefix("8.0.0.0", 8);
363 Prefix r = new Prefix("10.0.0.0", 24);
364 Prefix a = new Prefix("10.0.0.1", 32);
365
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200366 ptree.acquire(p.getAddress(), p.getPrefixLength());
367 ptree.acquire(q.getAddress(), q.getPrefixLength());
368 ptree.acquire(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800369
370 System.out.println("Traverse start");
371 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
372 Prefix p_result = new Prefix(node.key, node.keyBits);
373 }
374
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200375 PtreeNode n = ptree.match(a.getAddress(), a.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800376 if (n != null) {
377 System.out.println("Matched prefix for 10.0.0.1:");
378 Prefix x = new Prefix(n.key, n.keyBits);
379 ptree.delReference(n);
380 }
381
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200382 n = ptree.lookup(p.getAddress(), p.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800383 if (n != null) {
384 ptree.delReference(n);
385 ptree.delReference(n);
386 }
387 System.out.println("Traverse start");
388 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
389 Prefix p_result = new Prefix(node.key, node.keyBits);
390 }
391
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200392 n = ptree.lookup(q.getAddress(), q.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800393 if (n != null) {
394 ptree.delReference(n);
395 ptree.delReference(n);
396 }
397 System.out.println("Traverse start");
398 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
399 Prefix p_result = new Prefix(node.key, node.keyBits);
400 }
401
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200402 n = ptree.lookup(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800403 if (n != null) {
404 ptree.delReference(n);
405 ptree.delReference(n);
406 }
407 System.out.println("Traverse start");
408 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
409 Prefix p_result = new Prefix(node.key, node.keyBits);
410 }
411
412 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200413 */
pingping-lina2cbfad2013-03-07 08:39:21 +0800414
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200415 //TODO once the Ptree is object oriented this can go
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200416 private String getPrefixFromPtree(PtreeNode node){
417 InetAddress address = null;
418 try {
419 address = InetAddress.getByAddress(node.key);
420 } catch (UnknownHostException e1) {
421 //Should never happen is the reverse conversion has already been done
422 log.error("Malformed IP address");
423 return "";
424 }
425 return address.toString() + "/" + node.rib.masklen;
426 }
427
Jonathan Hart61ba9372013-05-19 20:10:29 -0700428 private void retrieveRib(){
429 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
430 String response = RestClient.get(url);
431
432 if (response.equals("")){
433 return;
434 }
435
436 response = response.replaceAll("\"", "'");
437 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
438 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
439 String router_id = jsonObj.getString("router-id");
440
441 int size = rib_json_array.size();
442
443 log.info("Retrived RIB of {} entries from BGPd", size);
444
445 for (int j = 0; j < size; j++) {
446 JSONObject second_json_object = rib_json_array.getJSONObject(j);
447 String prefix = second_json_object.getString("prefix");
448 String nexthop = second_json_object.getString("nexthop");
449
450 //insert each rib entry into the local rib;
451 String[] substring = prefix.split("/");
452 String prefix1 = substring[0];
453 String mask1 = substring[1];
454
455 Prefix p;
456 try {
457 p = new Prefix(prefix1, Integer.valueOf(mask1));
458 } catch (NumberFormatException e) {
459 log.warn("Wrong mask format in RIB JSON: {}", mask1);
460 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200461 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700462 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
463 continue;
464 }
465
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200466 //PtreeNode node = ptree.acquire(p.getAddress(), p.getPrefixLength());
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200467 Rib rib = new Rib(router_id, nexthop, p.getPrefixLength());
Jonathan Hart61ba9372013-05-19 20:10:29 -0700468
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200469 /*
Jonathan Hart61ba9372013-05-19 20:10:29 -0700470 if (node.rib != null) {
471 node.rib = null;
472 ptree.delReference(node);
473 }
474
475 node.rib = rib;
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200476 */
477
478 ptree.put(p, rib);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700479
Jonathan Hart2f740782013-08-04 00:49:21 +1200480 addPrefixFlows(p, rib);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700481 }
482 }
483
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200484 @Override
485 public void newRibUpdate(RibUpdate update) {
486 ribUpdates.add(update);
487 }
488
Jonathan Hart2f740782013-08-04 00:49:21 +1200489 public void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200490 Prefix prefix = update.getPrefix();
491
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200492 //PtreeNode node = ptree.acquire(prefix.getAddress(), prefix.getPrefixLength());
493 Rib rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200494
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200495 //if (node.rib != null) {
496 if (rib != null) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200497 //There was an existing nexthop for this prefix. This update supersedes that,
498 //so we need to remove the old flows for this prefix from the switches
499 deletePrefixFlows(prefix);
500
501 //Then remove the old nexthop from the Ptree
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200502 //node.rib = null;
503 //ptree.delReference(node);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200504 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200505
506 //Put the new nexthop in the Ptree
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200507 //node.rib = update.getRibEntry();
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200508
Jonathan Hart2f740782013-08-04 00:49:21 +1200509 //Push flows for the new <prefix, nexthop>
Jonathan Hart2f740782013-08-04 00:49:21 +1200510 addPrefixFlows(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200511 }
512
Jonathan Hart2f740782013-08-04 00:49:21 +1200513 public void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200514 Prefix prefix = update.getPrefix();
515
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200516 //PtreeNode node = ptree.lookup(prefix.getAddress(), prefix.getPrefixLength());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200517
518 /*
519 * Remove the flows from the switches before the rib is lost
520 * Theory: we could get a delete for a prefix not in the Ptree.
521 * This would result in a null node being returned. We could get a delete for
522 * a node that's not actually there, but is a aggregate node. This would result
523 * in a non-null node with a null rib. Only a non-null node with a non-null
524 * rib is an actual prefix in the Ptree.
525 */
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200526
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200527 /*
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200528 if (node != null && node.rib != null) {
529 if (update.getRibEntry().equals(node.rib)) {
530 node.rib = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200531 ptree.delReference(node);
532
Jonathan Hart2f740782013-08-04 00:49:21 +1200533 deletePrefixFlows(update.getPrefix());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200534 }
535 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200536 */
537
538 if (ptree.remove(prefix, update.getRibEntry())) {
539 /*
540 * Only delete flows if an entry was actually removed from the trie.
541 * If no entry was removed, the <prefix, nexthop> wasn't there so
542 * it's probably already been removed and we don't need to do anything
543 */
544 deletePrefixFlows(prefix);
545 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200546 }
547
Jonathan Hart2f740782013-08-04 00:49:21 +1200548 //TODO compatibility layer, used by beginRouting()
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200549 /*public void prefixAdded(PtreeNode node) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200550 Prefix prefix = null;
551 try {
552 prefix = new Prefix(node.key, node.rib.masklen);
Jonathan Hart32e18222013-08-07 22:05:42 +1200553 } catch (IllegalArgumentException e) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200554 log.error(" ", e);
555 }
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200556
Jonathan Hart2f740782013-08-04 00:49:21 +1200557 addPrefixFlows(prefix, node.rib);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200558 }*/
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200559
Jonathan Hart2f740782013-08-04 00:49:21 +1200560 private void addPrefixFlows(Prefix prefix, Rib rib) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200561 if (!topologyReady){
562 return;
563 }
564
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200565 //TODO before we do anything, we have to check that the RIB entry is still in the
566 //Ptree because it could have been removed while we were waiting for ARP.
567 //I think we'll have to make prefixAdded and prefixDelete atomic as well
568 //to protect against the prefix getting deleted while where trying to add it
Jonathan Hart2f740782013-08-04 00:49:21 +1200569
Jonathan Hartc824ad02013-07-03 15:58:45 +1200570 log.debug("New prefix {} added, next hop {}, routerId {}",
Jonathan Hart2f740782013-08-04 00:49:21 +1200571 new Object[] {prefix, rib.nextHop.getHostAddress(),
572 rib.routerId.getHostAddress()});
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200573
Jonathan Hartc824ad02013-07-03 15:58:45 +1200574 //TODO this is wrong, we shouldn't be dealing with BGP peers here.
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200575 //We need to figure out where the device is attached and what its
Jonathan Hartc824ad02013-07-03 15:58:45 +1200576 //mac address is by learning.
577 //The next hop is not necessarily the peer, and the peer's attachment
578 //point is not necessarily the next hop's attachment point.
Jonathan Hart2f740782013-08-04 00:49:21 +1200579 BgpPeer peer = bgpPeers.get(rib.nextHop);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700580
Jonathan Hartc824ad02013-07-03 15:58:45 +1200581 if (peer == null){
582 //TODO local router isn't in peers list so this will get thrown
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200583 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
Jonathan Hartc824ad02013-07-03 15:58:45 +1200584
585 //The other scenario is this is a route server route. In that
586 //case the next hop is not in our configuration
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200587 log.error("Couldn't find next hop router in router {} in config",
Jonathan Hart2f740782013-08-04 00:49:21 +1200588 rib.nextHop.getHostAddress());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700589 return; //just quit out here? This is probably a configuration error
590 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200591
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200592 //Get MAC address for peer from the ARP module
593 //TODO separate out the 'ask for MAC' bit to another method
594 byte[] peerMacAddress = proxyArp.getMacAddress(peer.getIpAddress());
595 if (peerMacAddress == null) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200596 //A RibUpdate is still a nice way to package them up
597 prefixesWaitingOnArp.put(peer.getIpAddress(),
598 new RibUpdate(Operation.UPDATE, prefix, rib));
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200599 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
600 return;
601 }
602
Jonathan Hartc824ad02013-07-03 15:58:45 +1200603 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200604
Jonathan Hartc824ad02013-07-03 15:58:45 +1200605 //Add a flow to rewrite mac for this prefix to all border switches
606 for (Interface srcInterface : interfaces.values()) {
607 if (srcInterface == peerInterface) {
608 //Don't push a flow for the switch where this peer is attached
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700609 continue;
610 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200611
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700612 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200613 srcInterface.getSwitchPort(),
614 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700615
616 if (shortestPath == null){
617 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200618 srcInterface.getSwitchPort(),
619 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700620 return; // just quit here?
621 }
622
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700623 //Set up the flow mod
624 OFFlowMod fm =
625 (OFFlowMod) floodlightProvider.getOFMessageFactory()
626 .getMessage(OFType.FLOW_MOD);
627
628 fm.setIdleTimeout((short)0)
629 .setHardTimeout((short)0)
630 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
631 .setCookie(MAC_RW_COOKIE)
632 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200633 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700634 .setLengthU(OFFlowMod.MINIMUM_LENGTH
635 + OFActionDataLayerDestination.MINIMUM_LENGTH
636 + OFActionOutput.MINIMUM_LENGTH);
637
638 OFMatch match = new OFMatch();
639 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200640 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700641
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200642 InetAddress address = null;
643 try {
Jonathan Hart2f740782013-08-04 00:49:21 +1200644 address = InetAddress.getByAddress(prefix.getAddress());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200645 } catch (UnknownHostException e1) {
646 //Should never happen is the reverse conversion has already been done
647 log.error("Malformed IP address");
648 return;
649 }
650
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200651 match.setFromCIDR(address.getHostAddress() + "/" +
Jonathan Hart2f740782013-08-04 00:49:21 +1200652 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(peerMacAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700659
660 //Set up output action
661 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200662 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700663
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200664 Port outputPort = shortestPath.flowEntries().get(0).outPort();
665 outputAction.setPort(outputPort.value());
666
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700667 List<OFAction> actions = new ArrayList<OFAction>();
668 actions.add(macRewriteAction);
669 actions.add(outputAction);
670 fm.setActions(actions);
671
672 //Write to switch
673 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200674 .get(srcInterface.getDpid());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700675
676 if (sw == null){
677 log.warn("Switch not found when pushing flow mod");
678 continue;
679 }
680
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200681 //TODO if prefix Added/Deleted are synchronized this shouldn't have to be
Jonathan Hart2f740782013-08-04 00:49:21 +1200682 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200683
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700684 List<OFMessage> msglist = new ArrayList<OFMessage>();
685 msglist.add(fm);
686 try {
687 sw.write(msglist, null);
688 sw.flush();
689 } catch (IOException e) {
690 log.error("Failure writing flow mod", e);
691 }
692 }
693 }
694
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200695 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200696 //TODO check delete/add synchronization
Jonathan Hart2f740782013-08-04 00:49:21 +1200697
698 private void deletePrefixFlows(Prefix prefix) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200699 if (!topologyReady) {
700 return;
701 }
702
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200703 log.debug("In deletePrefixFlows for {}", prefix);
Jonathan Hart2f740782013-08-04 00:49:21 +1200704
705 /*for (Map.Entry<Prefix, PushedFlowMod> entry : pushedFlows.entries()) {
706 log.debug("Pushed flow: {} => {}", entry.getKey(), entry.getValue());
707 }*/
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200708
709 Collection<PushedFlowMod> pushedFlowMods
Jonathan Hart2f740782013-08-04 00:49:21 +1200710 = pushedFlows.removeAll(prefix);
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200711
712 for (PushedFlowMod pfm : pushedFlowMods) {
713 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
714 new Object[] {HexString.toHexString(pfm.getDpid()),
715 pfm.getFlowMod().getMatch().getNetworkDestination() +
716 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
717 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
718 .getDataLayerAddress())});
719
720 OFFlowMod fm = pfm.getFlowMod();
721
722 fm.setCommand(OFFlowMod.OFPFC_DELETE)
Jonathan Hart2f740782013-08-04 00:49:21 +1200723 .setOutPort(OFPort.OFPP_NONE)
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200724 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
725
726 fm.getActions().clear();
727
728 IOFSwitch sw = floodlightProvider.getSwitches().get(pfm.getDpid());
729 if (sw == null) {
730 log.warn("Switch not found when pushing delete flow mod");
731 continue;
732 }
733
734 try {
735 sw.write(fm, null);
736 sw.flush();
737 } catch (IOException e) {
738 log.error("Failure writing flow mod", e);
739 }
740 }
741 }
742
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700743 /*
744 * On startup we need to calculate a full mesh of paths between all gateway
745 * switches
746 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200747 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700748 //For each border router, calculate and install a path from every other
749 //border switch to said border router. However, don't install the entry
750 //in to the first hop switch, as we need to install an entry to rewrite
751 //for each prefix received. This will be done later when prefixes have
752 //actually been received.
753
Jonathan Hartc824ad02013-07-03 15:58:45 +1200754 for (BgpPeer peer : bgpPeers.values()) {
755 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200756
757 //See if we know the MAC address of the peer. If not we can't
758 //do anything until we learn it
759 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
760 if (mac == null) {
761 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
762 //Put in the pending paths list first
763 pathsWaitingOnArp.put(peer.getIpAddress(),
764 new PathUpdate(peerInterface, peer.getIpAddress()));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700765
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200766 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
767 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700768 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200769
770 //If we know the MAC, lets go ahead and push the paths to this peer
771 calculateAndPushPath(peerInterface, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700772 }
773 }
774
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200775 private void calculateAndPushPath(Interface dstInterface, MACAddress dstMacAddress) {
776 for (Interface srcInterface : interfaces.values()) {
777 if (dstInterface.equals(srcInterface.getName())){
778 continue;
779 }
780
781 DataPath shortestPath = topoRouteService.getShortestPath(
782 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
783
784 if (shortestPath == null){
785 log.debug("Shortest path between {} and {} not found",
786 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
787 return; // just quit here?
788 }
789
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200790 installPath(shortestPath.flowEntries(), dstMacAddress);
791 }
792 }
793
794 private void installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700795 //Set up the flow mod
796 OFFlowMod fm =
797 (OFFlowMod) floodlightProvider.getOFMessageFactory()
798 .getMessage(OFType.FLOW_MOD);
799
800 OFActionOutput action = new OFActionOutput();
801 action.setMaxLength((short)0xffff);
802 List<OFAction> actions = new ArrayList<OFAction>();
803 actions.add(action);
804
805 fm.setIdleTimeout((short)0)
806 .setHardTimeout((short)0)
807 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
808 .setCookie(L2_FWD_COOKIE)
809 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700810 .setActions(actions)
811 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
812
813 //Don't push the first flow entry. We need to push entries in the
814 //first switch based on IP prefix which we don't know yet.
815 for (int i = 1; i < flowEntries.size(); i++){
816 FlowEntry flowEntry = flowEntries.get(i);
817
818 OFMatch match = new OFMatch();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200819 //TODO Again using MAC address from configuration
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200820 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700821 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
822 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
823
824 fm.setMatch(match);
825
826 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
827
828 if (sw == null){
829 log.warn("Switch not found when pushing flow mod");
830 continue;
831 }
832
833 List<OFMessage> msglist = new ArrayList<OFMessage>();
834 msglist.add(fm);
835 try {
836 sw.write(msglist, null);
837 sw.flush();
838 } catch (IOException e) {
839 log.error("Failure writing flow mod", e);
840 }
841
842 try {
843 fm = fm.clone();
844 } catch (CloneNotSupportedException e1) {
845 log.error("Failure cloning flow mod", e1);
846 }
847 }
848 }
849
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200850 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200851 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200852 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
853
854 DataPath path = topoRouteService.getShortestPath(
855 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
856
857 if (path == null){
858 log.debug("Unable to compute path for BGP traffic for {}",
859 bgpPeer.getIpAddress());
860 continue;
861 }
862
863 //Set up the flow mod
864 OFFlowMod fm =
865 (OFFlowMod) floodlightProvider.getOFMessageFactory()
866 .getMessage(OFType.FLOW_MOD);
867
868 OFActionOutput action = new OFActionOutput();
869 action.setMaxLength((short)0xffff);
870 List<OFAction> actions = new ArrayList<OFAction>();
871 actions.add(action);
872
873 fm.setIdleTimeout((short)0)
874 .setHardTimeout((short)0)
875 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
876 .setCookie(BGP_COOKIE)
877 .setCommand(OFFlowMod.OFPFC_ADD)
878 .setPriority(SDNIP_PRIORITY)
879 .setActions(actions)
880 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
881
882 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
883 OFMatch forwardMatchSrc = new OFMatch();
884
885
886 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
887 + "/32";
888 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
889 + "/32";
890
891 //Common match fields
892 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
893 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
894 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
895 forwardMatchSrc.setTransportDestination(BGP_PORT);
896 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
897 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
898
899
900 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
901
902 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
903 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
904
905 OFMatch forwardMatchDst = forwardMatchSrc.clone();
906
907 forwardMatchSrc.setTransportSource(BGP_PORT);
908 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
909 forwardMatchDst.setTransportDestination(BGP_PORT);
910 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
911
912 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
913 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
914
915 OFMatch reverseMatchDst = reverseMatchSrc.clone();
916
917 reverseMatchSrc.setTransportSource(BGP_PORT);
918 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
919 reverseMatchDst.setTransportDestination(BGP_PORT);
920 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
921
922 fm.setMatch(forwardMatchSrc);
923
924 for (FlowEntry flowEntry : path.flowEntries()){
925 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
926 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
927 try {
928 forwardFlowModSrc = fm.clone();
929 forwardFlowModDst = fm.clone();
930 reverseFlowModSrc = fm.clone();
931 reverseFlowModDst = fm.clone();
932 } catch (CloneNotSupportedException e) {
933 log.warn("Clone failed", e);
934 continue;
935 }
936
937 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
938 forwardFlowModSrc.setMatch(forwardMatchSrc);
939 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
940 .setPort(flowEntry.outPort().value());
941
942 forwardMatchDst.setInputPort(flowEntry.inPort().value());
943 forwardFlowModDst.setMatch(forwardMatchDst);
944 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
945 .setPort(flowEntry.outPort().value());
946
947 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
948 reverseFlowModSrc.setMatch(reverseMatchSrc);
949 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
950 .setPort(flowEntry.inPort().value());
951
952 reverseMatchDst.setInputPort(flowEntry.outPort().value());
953 reverseFlowModDst.setMatch(reverseMatchDst);
954 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
955 .setPort(flowEntry.inPort().value());
956
957 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
958
959 //Hopefully the switch is there
960 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
961 msgList.add(forwardFlowModSrc);
962 msgList.add(forwardFlowModDst);
963 msgList.add(reverseFlowModSrc);
964 msgList.add(reverseFlowModDst);
965
966 try {
967 sw.write(msgList, null);
968 sw.flush();
969 } catch (IOException e) {
970 log.error("Failure writing flow mod", e);
971 }
972 }
973 }
974 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200975
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200976 @Override
977 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
978 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
979 MACAddress.valueOf(macAddress).toString());
980
981 Set<PathUpdate> pathsToPush = pathsWaitingOnArp.removeAll(ipAddress);
982
983 for (PathUpdate update : pathsToPush) {
984 log.debug("Pushing path to {} at {} on {}", new Object[] {
985 update.getDstIpAddress().getHostAddress(),
986 MACAddress.valueOf(macAddress),
987 update.getDstInterface().getSwitchPort()});
988 calculateAndPushPath(update.getDstInterface(),
989 MACAddress.valueOf(macAddress));
990 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200991
992 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
993
994 for (RibUpdate update : prefixesToPush) {
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200995 //These will always be adds
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200996 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
997 update.getRibEntry().nextHop.getHostAddress());
Jonathan Hart2f740782013-08-04 00:49:21 +1200998 addPrefixFlows(update.getPrefix(), update.getRibEntry());
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200999 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001000 }
1001
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001002 private void beginRouting(){
1003 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001004 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001005 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001006
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001007 //Traverse ptree and create flows for all routes
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001008 /*
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001009 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
1010 if (node.rib != null){
1011 prefixAdded(node);
1012 }
1013 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001014 */
1015
1016 synchronized (ptree) {
1017 Iterator<IPatriciaTrie.Entry> it = ptree.iterator();
1018 while (it.hasNext()) {
1019 IPatriciaTrie.Entry entry = it.next();
1020 addPrefixFlows(entry.getPrefix(), entry.getRib());
1021 }
1022 }
1023
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001024 }
1025
1026 private void checkSwitchesConnected(){
1027 for (String dpid : switches){
1028 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1029 log.debug("Not all switches are here yet");
1030 return;
1031 }
1032 }
1033 switchesConnected = true;
1034 }
1035
Jonathan Hartc824ad02013-07-03 15:58:45 +12001036 //Actually we only need to go half way round to verify full mesh connectivity
1037 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001038 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001039 for (Interface dstInterface : interfaces.values()) {
1040 for (Interface srcInterface : interfaces.values()) {
1041 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001042 continue;
1043 }
1044
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001045 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001046 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001047
1048 if (shortestPath == null){
1049 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001050 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001051 return;
1052 }
1053 }
1054 }
1055 topologyReady = true;
1056 }
1057
1058 private void checkStatus(){
1059 log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
1060
1061 if (!switchesConnected){
1062 checkSwitchesConnected();
1063 }
1064 boolean oldTopologyReadyStatus = topologyReady;
1065 if (switchesConnected && !topologyReady){
1066 checkTopologyReady();
1067 }
1068 if (!oldTopologyReadyStatus && topologyReady){
1069 beginRouting();
1070 }
1071 }
1072
pingping-lina2cbfad2013-03-07 08:39:21 +08001073 @Override
1074 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +08001075 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001076 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -07001077 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +08001078
Jonathan Hartc7ca35d2013-06-25 20:54:25 +12001079 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
1080
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001081 ExecutorService e = Executors.newSingleThreadExecutor(
1082 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
1083
1084
1085 e.execute(new Runnable() {
1086 @Override
1087 public void run() {
1088 doUpdatesThread();
1089 }
1090 });
1091
Jonathan Hart61ba9372013-05-19 20:10:29 -07001092 //Retrieve the RIB from BGPd during startup
1093 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +08001094 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001095
1096 private void doUpdatesThread() {
1097 boolean interrupted = false;
1098 try {
1099 while (true) {
1100 try {
1101 RibUpdate update = ribUpdates.take();
1102 switch (update.getOperation()){
1103 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001104 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001105 break;
1106 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001107 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001108 break;
1109 }
1110 } catch (InterruptedException e) {
1111 interrupted = true;
1112 }
1113 }
1114 } finally {
1115 if (interrupted) {
1116 Thread.currentThread().interrupt();
1117 }
1118 }
1119 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001120
1121 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001122 public void topologyChanged() {
1123 //There seems to be more topology events than there should be. Lots of link
1124 //updated, port up and switch updated on what should be a fairly static topology
pingping-lina2cbfad2013-03-07 08:39:21 +08001125
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001126 boolean refreshNeeded = false;
1127 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1128 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1129 //We don't need to recalculate anything for just link updates
1130 //They happen way too frequently (may be a bug in our link discovery)
1131 refreshNeeded = true;
1132 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001133
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001134 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001135
Jonathan Hart98957bf2013-07-01 14:49:24 +12001136 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1137 synchronized (linkUpdates) {
1138 linkUpdates.add(ldu);
1139 }
1140 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001141 }
1142
1143 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001144 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001145 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001146 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001147
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001148 //TODO determine whether we need to listen for switch joins
1149 @Override
1150 public void addedSwitch(IOFSwitch sw) {
1151 //checkStatus();
1152 }
1153
1154 @Override
1155 public void removedSwitch(IOFSwitch sw) {
1156 // TODO Auto-generated method stub
1157 }
1158
1159 @Override
1160 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001161
1162 @Override
1163 public String getName() {
1164 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +08001165 }
1166}