blob: c36d4a577c46eebabc56e2fbb929e319ac8d7252 [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;
pingping-lina2cbfad2013-03-07 08:39:21 +08006import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07007import java.util.Collection;
pingping-lina2cbfad2013-03-07 08:39:21 +08008import java.util.HashMap;
Jonathan Hart98957bf2013-07-01 14:49:24 +12009import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070010import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070011import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120012import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120013import java.util.concurrent.BlockingQueue;
14import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120015import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120016import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080019
Jonathan Hart61ba9372013-05-19 20:10:29 -070020import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070021import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120022import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120027import net.floodlightcontroller.core.util.SingletonTask;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070028import net.floodlightcontroller.devicemanager.IDeviceService;
29import net.floodlightcontroller.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120030import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080031import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120032import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080033import net.floodlightcontroller.topology.ITopologyListener;
34import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120035import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120036import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
Jonathan Hart98957bf2013-07-01 14:49:24 +120037import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070038import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120039import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070040import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
41import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120042import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120043import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070044import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070045import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120046import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070048import net.onrc.onos.ofcontroller.util.Port;
49import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080050import net.sf.json.JSONArray;
51import net.sf.json.JSONObject;
52import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080053
Jonathan Hartd1f23252013-06-13 15:17:05 +120054import org.codehaus.jackson.JsonParseException;
55import org.codehaus.jackson.map.JsonMappingException;
56import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070057import org.openflow.protocol.OFFlowMod;
58import org.openflow.protocol.OFMatch;
59import org.openflow.protocol.OFMessage;
60import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120061import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070062import org.openflow.protocol.OFType;
63import org.openflow.protocol.action.OFAction;
64import org.openflow.protocol.action.OFActionDataLayerDestination;
65import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120066import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080067import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
69
Jonathan Hart4dfc3652013-08-02 20:22:36 +120070import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120071import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120072import com.google.common.collect.Multimaps;
73import com.google.common.collect.SetMultimap;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120074import com.google.common.util.concurrent.ThreadFactoryBuilder;
75
Jonathan Hart1236a9b2013-06-18 22:10:05 +120076public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart4dfc3652013-08-02 20:22:36 +120077 ITopologyListener, IOFSwitchListener,
78 IArpRequester {
pingping-lina2cbfad2013-03-07 08:39:21 +080079
80 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
81
82 protected IFloodlightProviderService floodlightProvider;
83 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070084 protected ITopoRouteService topoRouteService;
85 protected IDeviceService devices;
86 protected IRestApiService restApi;
87
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120088 protected ProxyArpManager proxyArp;
89
Jonathan Hartd7e158d2013-08-07 23:04:48 +120090 //protected static Ptree ptree;
91 protected IPatriciaTrie ptree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120092 protected BlockingQueue<RibUpdate> ribUpdates;
93
Jonathan Hart61ba9372013-05-19 20:10:29 -070094 protected String bgpdRestIp;
95 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120096 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070097
98 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
99 //the controller/OS should hand out cookie IDs to prevent conflicts.
100 protected final long APP_COOKIE = 0xa0000000000000L;
101 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
102 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
103 //Cookie for flows in ingress switches that rewrite the MAC address
104 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200105 //Cookie for flows that setup BGP paths
106 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200107 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
108 //need to be higher priority than this otherwise the rewrite may not get done
109 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700110
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200111 protected final short BGP_PORT = 179;
112
Jonathan Hart98957bf2013-07-01 14:49:24 +1200113 protected final int TOPO_DETECTION_WAIT = 2; //seconds
114
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200115 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200116 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200117 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200118 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200119 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200120
121 //True when all switches have connected
122 protected volatile boolean switchesConnected = false;
123 //True when we have a full mesh of shortest paths between gateways
124 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200125
Jonathan Hart98957bf2013-07-01 14:49:24 +1200126 protected ArrayList<LDUpdate> linkUpdates;
127 protected SingletonTask topologyChangeDetectorTask;
128
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200129 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
130 protected SetMultimap<InetAddress, PathUpdate> pathsWaitingOnArp;
131
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200132 protected ExecutorService bgpUpdatesExecutor;
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
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200255 //ptree = new Ptree(32);
256 ptree = new PatriciaTrie(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200257
258 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200259
pingping-lina2cbfad2013-03-07 08:39:21 +0800260 // Register floodlight provider and REST handler.
261 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800262 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700263 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200264 restApi = context.getServiceImpl(IRestApiService.class);
265
266 //TODO We'll initialise this here for now, but it should really be done as
267 //part of the controller core
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200268 proxyArp = new ProxyArpManager(floodlightProvider, topology, devices);
pingping-lina2cbfad2013-03-07 08:39:21 +0800269
Jonathan Hart98957bf2013-07-01 14:49:24 +1200270 linkUpdates = new ArrayList<LDUpdate>();
271 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
272 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700273
274 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200275
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200276 pathsWaitingOnArp = Multimaps.synchronizedSetMultimap(
277 HashMultimap.<InetAddress, PathUpdate>create());
278 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
279 HashMultimap.<InetAddress, RibUpdate>create());
280
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200281 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
282
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200283 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
284 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
285
Jonathan Hart61ba9372013-05-19 20:10:29 -0700286 //Read in config values
287 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
288 if (bgpdRestIp == null){
289 log.error("BgpdRestIp property not found in config file");
290 System.exit(1);
291 }
292 else {
293 log.info("BgpdRestIp set to {}", bgpdRestIp);
294 }
295
296 routerId = context.getConfigParams(this).get("RouterId");
297 if (routerId == null){
298 log.error("RouterId property not found in config file");
299 System.exit(1);
300 }
301 else {
302 log.info("RouterId set to {}", routerId);
303 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200304
Jonathan Hart9575cb62013-07-05 13:43:49 +1200305 String configFilenameParameter = context.getConfigParams(this).get("configfile");
306 if (configFilenameParameter != null){
307 configFilename = configFilenameParameter;
308 }
309 log.debug("Config file set to {}", configFilename);
310
311 readGatewaysConfiguration(configFilename);
pingping-lina2cbfad2013-03-07 08:39:21 +0800312 // Test.
313 //test();
314 }
315
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200316 //public Ptree getPtree() {
317 public IPatriciaTrie getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800318 return ptree;
319 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700320
321 public void clearPtree() {
322 //ptree = null;
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200323 //ptree = new Ptree(32);
324 ptree = new PatriciaTrie(32);
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 getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700328 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800329 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700330
pingping-line2a09ca2013-03-23 09:33:58 +0800331 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700332 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800333 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800334
335 // Return nexthop address as byte array.
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200336 /*
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200337 public RibEntry lookupRib(byte[] dest) {
pingping-lina2cbfad2013-03-07 08:39:21 +0800338 if (ptree == null) {
339 log.debug("lookupRib: ptree null");
340 return null;
341 }
342
343 PtreeNode node = ptree.match(dest, 32);
344 if (node == null) {
345 log.debug("lookupRib: ptree node null");
346 return null;
347 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700348
pingping-lina2cbfad2013-03-07 08:39:21 +0800349 if (node.rib == null) {
350 log.debug("lookupRib: ptree rib null");
351 return null;
352 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700353
pingping-lina2cbfad2013-03-07 08:39:21 +0800354 ptree.delReference(node);
355
356 return node.rib;
357 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200358 */
pingping-lina2cbfad2013-03-07 08:39:21 +0800359
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200360 /*
Jonathan Hart61ba9372013-05-19 20:10:29 -0700361 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800362 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700363 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800364 System.out.println("Here it is");
365 Prefix p = new Prefix("128.0.0.0", 8);
366 Prefix q = new Prefix("8.0.0.0", 8);
367 Prefix r = new Prefix("10.0.0.0", 24);
368 Prefix a = new Prefix("10.0.0.1", 32);
369
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200370 ptree.acquire(p.getAddress(), p.getPrefixLength());
371 ptree.acquire(q.getAddress(), q.getPrefixLength());
372 ptree.acquire(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800373
374 System.out.println("Traverse start");
375 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
376 Prefix p_result = new Prefix(node.key, node.keyBits);
377 }
378
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200379 PtreeNode n = ptree.match(a.getAddress(), a.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800380 if (n != null) {
381 System.out.println("Matched prefix for 10.0.0.1:");
382 Prefix x = new Prefix(n.key, n.keyBits);
383 ptree.delReference(n);
384 }
385
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200386 n = ptree.lookup(p.getAddress(), p.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800387 if (n != null) {
388 ptree.delReference(n);
389 ptree.delReference(n);
390 }
391 System.out.println("Traverse start");
392 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
393 Prefix p_result = new Prefix(node.key, node.keyBits);
394 }
395
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200396 n = ptree.lookup(q.getAddress(), q.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800397 if (n != null) {
398 ptree.delReference(n);
399 ptree.delReference(n);
400 }
401 System.out.println("Traverse start");
402 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
403 Prefix p_result = new Prefix(node.key, node.keyBits);
404 }
405
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200406 n = ptree.lookup(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800407 if (n != null) {
408 ptree.delReference(n);
409 ptree.delReference(n);
410 }
411 System.out.println("Traverse start");
412 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
413 Prefix p_result = new Prefix(node.key, node.keyBits);
414 }
415
416 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200417 */
pingping-lina2cbfad2013-03-07 08:39:21 +0800418
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200419 //TODO once the Ptree is object oriented this can go
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200420 /*
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200421 private String getPrefixFromPtree(PtreeNode node){
422 InetAddress address = null;
423 try {
424 address = InetAddress.getByAddress(node.key);
425 } catch (UnknownHostException e1) {
426 //Should never happen is the reverse conversion has already been done
427 log.error("Malformed IP address");
428 return "";
429 }
430 return address.toString() + "/" + node.rib.masklen;
431 }
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200432 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200433
Jonathan Hart61ba9372013-05-19 20:10:29 -0700434 private void retrieveRib(){
435 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
436 String response = RestClient.get(url);
437
438 if (response.equals("")){
439 return;
440 }
441
442 response = response.replaceAll("\"", "'");
443 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
444 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
445 String router_id = jsonObj.getString("router-id");
446
447 int size = rib_json_array.size();
448
449 log.info("Retrived RIB of {} entries from BGPd", size);
450
451 for (int j = 0; j < size; j++) {
452 JSONObject second_json_object = rib_json_array.getJSONObject(j);
453 String prefix = second_json_object.getString("prefix");
454 String nexthop = second_json_object.getString("nexthop");
455
456 //insert each rib entry into the local rib;
457 String[] substring = prefix.split("/");
458 String prefix1 = substring[0];
459 String mask1 = substring[1];
460
461 Prefix p;
462 try {
463 p = new Prefix(prefix1, Integer.valueOf(mask1));
464 } catch (NumberFormatException e) {
465 log.warn("Wrong mask format in RIB JSON: {}", mask1);
466 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200467 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700468 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
469 continue;
470 }
471
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200472 //PtreeNode node = ptree.acquire(p.getAddress(), p.getPrefixLength());
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200473 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700474
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200475 /*
Jonathan Hart61ba9372013-05-19 20:10:29 -0700476 if (node.rib != null) {
477 node.rib = null;
478 ptree.delReference(node);
479 }
480
481 node.rib = rib;
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200482 */
483
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200484 //ptree.put(p, rib);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700485
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200486 //addPrefixFlows(p, rib);
487 try {
488 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
489 } catch (InterruptedException e) {
490 log.debug("Interrupted while pushing onto update queue");
491 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700492 }
493 }
494
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200495 @Override
496 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200497 try {
498 ribUpdates.put(update);
499 } catch (InterruptedException e) {
500 // TODO Auto-generated catch block
501 log.debug(" ", e);
502 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200503 }
504
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200505 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200506 Prefix prefix = update.getPrefix();
507
Jonathan Hart9ea31212013-08-12 21:40:34 +1200508 log.debug("Processing prefix add {}", prefix);
509
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200510 //PtreeNode node = ptree.acquire(prefix.getAddress(), prefix.getPrefixLength());
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200511 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200512
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200513 //if (node.rib != null) {
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200514 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200515 //There was an existing nexthop for this prefix. This update supersedes that,
516 //so we need to remove the old flows for this prefix from the switches
517 deletePrefixFlows(prefix);
518
519 //Then remove the old nexthop from the Ptree
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200520 //node.rib = null;
521 //ptree.delReference(node);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200522 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200523
524 //Put the new nexthop in the Ptree
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200525 //node.rib = update.getRibEntry();
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200526
Jonathan Hart2f740782013-08-04 00:49:21 +1200527 //Push flows for the new <prefix, nexthop>
Jonathan Hart2f740782013-08-04 00:49:21 +1200528 addPrefixFlows(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200529 }
530
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200531 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200532 Prefix prefix = update.getPrefix();
533
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200534 //PtreeNode node = ptree.lookup(prefix.getAddress(), prefix.getPrefixLength());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200535
536 /*
537 * Remove the flows from the switches before the rib is lost
538 * Theory: we could get a delete for a prefix not in the Ptree.
539 * This would result in a null node being returned. We could get a delete for
540 * a node that's not actually there, but is a aggregate node. This would result
541 * in a non-null node with a null rib. Only a non-null node with a non-null
542 * rib is an actual prefix in the Ptree.
543 */
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200544
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200545 /*
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200546 if (node != null && node.rib != null) {
547 if (update.getRibEntry().equals(node.rib)) {
548 node.rib = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200549 ptree.delReference(node);
550
Jonathan Hart2f740782013-08-04 00:49:21 +1200551 deletePrefixFlows(update.getPrefix());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200552 }
553 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200554 */
555
556 if (ptree.remove(prefix, update.getRibEntry())) {
557 /*
558 * Only delete flows if an entry was actually removed from the trie.
559 * If no entry was removed, the <prefix, nexthop> wasn't there so
560 * it's probably already been removed and we don't need to do anything
561 */
562 deletePrefixFlows(prefix);
563 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200564 }
565
Jonathan Hart2f740782013-08-04 00:49:21 +1200566 //TODO compatibility layer, used by beginRouting()
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200567 /*public void prefixAdded(PtreeNode node) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200568 Prefix prefix = null;
569 try {
570 prefix = new Prefix(node.key, node.rib.masklen);
Jonathan Hart32e18222013-08-07 22:05:42 +1200571 } catch (IllegalArgumentException e) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200572 log.error(" ", e);
573 }
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200574
Jonathan Hart2f740782013-08-04 00:49:21 +1200575 addPrefixFlows(prefix, node.rib);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200576 }*/
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200577
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200578 private void addPrefixFlows(Prefix prefix, RibEntry rib) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200579 if (!topologyReady){
580 return;
581 }
582
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200583 //TODO before we do anything, we have to check that the RIB entry is still in the
584 //Ptree because it could have been removed while we were waiting for ARP.
585 //I think we'll have to make prefixAdded and prefixDelete atomic as well
586 //to protect against the prefix getting deleted while where trying to add it
Jonathan Hart2f740782013-08-04 00:49:21 +1200587
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200588 log.debug("New prefix {} added, next hop {}",
589 prefix, rib.getNextHop().getHostAddress());
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200590
Jonathan Hartc824ad02013-07-03 15:58:45 +1200591 //TODO this is wrong, we shouldn't be dealing with BGP peers here.
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200592 //We need to figure out where the device is attached and what its
Jonathan Hartc824ad02013-07-03 15:58:45 +1200593 //mac address is by learning.
594 //The next hop is not necessarily the peer, and the peer's attachment
595 //point is not necessarily the next hop's attachment point.
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200596 BgpPeer peer = bgpPeers.get(rib.getNextHop());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700597
Jonathan Hartc824ad02013-07-03 15:58:45 +1200598 if (peer == null){
599 //TODO local router isn't in peers list so this will get thrown
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200600 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
Jonathan Hartc824ad02013-07-03 15:58:45 +1200601
602 //The other scenario is this is a route server route. In that
603 //case the next hop is not in our configuration
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200604 log.error("Couldn't find next hop router in router {} in config",
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200605 rib.getNextHop().getHostAddress());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700606 return; //just quit out here? This is probably a configuration error
607 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200608
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200609 //Get MAC address for peer from the ARP module
610 //TODO separate out the 'ask for MAC' bit to another method
611 byte[] peerMacAddress = proxyArp.getMacAddress(peer.getIpAddress());
612 if (peerMacAddress == null) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200613 //A RibUpdate is still a nice way to package them up
614 prefixesWaitingOnArp.put(peer.getIpAddress(),
615 new RibUpdate(Operation.UPDATE, prefix, rib));
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200616 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
617 return;
618 }
619
Jonathan Hartc824ad02013-07-03 15:58:45 +1200620 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200621
Jonathan Hartc824ad02013-07-03 15:58:45 +1200622 //Add a flow to rewrite mac for this prefix to all border switches
623 for (Interface srcInterface : interfaces.values()) {
624 if (srcInterface == peerInterface) {
625 //Don't push a flow for the switch where this peer is attached
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700626 continue;
627 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200628
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700629 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200630 srcInterface.getSwitchPort(),
631 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700632
633 if (shortestPath == null){
634 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200635 srcInterface.getSwitchPort(),
636 peerInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700637 return; // just quit here?
638 }
639
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700640 //Set up the flow mod
641 OFFlowMod fm =
642 (OFFlowMod) floodlightProvider.getOFMessageFactory()
643 .getMessage(OFType.FLOW_MOD);
644
645 fm.setIdleTimeout((short)0)
646 .setHardTimeout((short)0)
647 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
648 .setCookie(MAC_RW_COOKIE)
649 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200650 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700651 .setLengthU(OFFlowMod.MINIMUM_LENGTH
652 + OFActionDataLayerDestination.MINIMUM_LENGTH
653 + OFActionOutput.MINIMUM_LENGTH);
654
655 OFMatch match = new OFMatch();
656 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200657 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700658
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200659 /*
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200660 InetAddress address = null;
661 try {
Jonathan Hart2f740782013-08-04 00:49:21 +1200662 address = InetAddress.getByAddress(prefix.getAddress());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200663 } catch (UnknownHostException e1) {
664 //Should never happen is the reverse conversion has already been done
665 log.error("Malformed IP address");
666 return;
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200667 }*/
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200668
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200669 //match.setFromCIDR(address.getHostAddress() + "/" +
670 // prefix.getPrefixLength(), OFMatch.STR_NW_DST);
671 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200672 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700673
674 //Set up MAC rewrite action
675 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200676 //TODO the peer's mac address is not necessarily the next hop's...
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200677 macRewriteAction.setDataLayerAddress(peerMacAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700678
679 //Set up output action
680 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200681 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700682
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200683 Port outputPort = shortestPath.flowEntries().get(0).outPort();
684 outputAction.setPort(outputPort.value());
685
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700686 List<OFAction> actions = new ArrayList<OFAction>();
687 actions.add(macRewriteAction);
688 actions.add(outputAction);
689 fm.setActions(actions);
690
691 //Write to switch
692 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200693 .get(srcInterface.getDpid());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700694
695 if (sw == null){
696 log.warn("Switch not found when pushing flow mod");
697 continue;
698 }
699
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200700 //TODO if prefix Added/Deleted are synchronized this shouldn't have to be
Jonathan Hart2f740782013-08-04 00:49:21 +1200701 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200702
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700703 List<OFMessage> msglist = new ArrayList<OFMessage>();
704 msglist.add(fm);
705 try {
706 sw.write(msglist, null);
707 sw.flush();
708 } catch (IOException e) {
709 log.error("Failure writing flow mod", e);
710 }
711 }
712 }
713
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200714 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200715 //TODO check delete/add synchronization
Jonathan Hart2f740782013-08-04 00:49:21 +1200716
717 private void deletePrefixFlows(Prefix prefix) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200718 if (!topologyReady) {
719 return;
720 }
721
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200722 log.debug("In deletePrefixFlows for {}", prefix);
Jonathan Hart2f740782013-08-04 00:49:21 +1200723
724 /*for (Map.Entry<Prefix, PushedFlowMod> entry : pushedFlows.entries()) {
725 log.debug("Pushed flow: {} => {}", entry.getKey(), entry.getValue());
726 }*/
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200727
728 Collection<PushedFlowMod> pushedFlowMods
Jonathan Hart2f740782013-08-04 00:49:21 +1200729 = pushedFlows.removeAll(prefix);
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200730
731 for (PushedFlowMod pfm : pushedFlowMods) {
732 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
733 new Object[] {HexString.toHexString(pfm.getDpid()),
734 pfm.getFlowMod().getMatch().getNetworkDestination() +
735 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
736 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
737 .getDataLayerAddress())});
738
739 OFFlowMod fm = pfm.getFlowMod();
740
741 fm.setCommand(OFFlowMod.OFPFC_DELETE)
Jonathan Hart2f740782013-08-04 00:49:21 +1200742 .setOutPort(OFPort.OFPP_NONE)
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200743 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
744
745 fm.getActions().clear();
746
747 IOFSwitch sw = floodlightProvider.getSwitches().get(pfm.getDpid());
748 if (sw == null) {
749 log.warn("Switch not found when pushing delete flow mod");
750 continue;
751 }
752
753 try {
754 sw.write(fm, null);
755 sw.flush();
756 } catch (IOException e) {
757 log.error("Failure writing flow mod", e);
758 }
759 }
760 }
761
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700762 /*
763 * On startup we need to calculate a full mesh of paths between all gateway
764 * switches
765 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200766 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700767 //For each border router, calculate and install a path from every other
768 //border switch to said border router. However, don't install the entry
769 //in to the first hop switch, as we need to install an entry to rewrite
770 //for each prefix received. This will be done later when prefixes have
771 //actually been received.
772
Jonathan Hartc824ad02013-07-03 15:58:45 +1200773 for (BgpPeer peer : bgpPeers.values()) {
774 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200775
776 //See if we know the MAC address of the peer. If not we can't
777 //do anything until we learn it
778 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
779 if (mac == null) {
780 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
781 //Put in the pending paths list first
782 pathsWaitingOnArp.put(peer.getIpAddress(),
783 new PathUpdate(peerInterface, peer.getIpAddress()));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700784
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200785 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
786 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700787 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200788
789 //If we know the MAC, lets go ahead and push the paths to this peer
790 calculateAndPushPath(peerInterface, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700791 }
792 }
793
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200794 private void calculateAndPushPath(Interface dstInterface, MACAddress dstMacAddress) {
795 for (Interface srcInterface : interfaces.values()) {
796 if (dstInterface.equals(srcInterface.getName())){
797 continue;
798 }
799
800 DataPath shortestPath = topoRouteService.getShortestPath(
801 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
802
803 if (shortestPath == null){
804 log.debug("Shortest path between {} and {} not found",
805 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
806 return; // just quit here?
807 }
808
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200809 installPath(shortestPath.flowEntries(), dstMacAddress);
810 }
811 }
812
813 private void installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700814 //Set up the flow mod
815 OFFlowMod fm =
816 (OFFlowMod) floodlightProvider.getOFMessageFactory()
817 .getMessage(OFType.FLOW_MOD);
818
819 OFActionOutput action = new OFActionOutput();
820 action.setMaxLength((short)0xffff);
821 List<OFAction> actions = new ArrayList<OFAction>();
822 actions.add(action);
823
824 fm.setIdleTimeout((short)0)
825 .setHardTimeout((short)0)
826 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
827 .setCookie(L2_FWD_COOKIE)
828 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700829 .setActions(actions)
830 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
831
832 //Don't push the first flow entry. We need to push entries in the
833 //first switch based on IP prefix which we don't know yet.
834 for (int i = 1; i < flowEntries.size(); i++){
835 FlowEntry flowEntry = flowEntries.get(i);
836
837 OFMatch match = new OFMatch();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200838 //TODO Again using MAC address from configuration
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200839 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700840 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
841 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
842
843 fm.setMatch(match);
844
845 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
846
847 if (sw == null){
848 log.warn("Switch not found when pushing flow mod");
849 continue;
850 }
851
852 List<OFMessage> msglist = new ArrayList<OFMessage>();
853 msglist.add(fm);
854 try {
855 sw.write(msglist, null);
856 sw.flush();
857 } catch (IOException e) {
858 log.error("Failure writing flow mod", e);
859 }
860
861 try {
862 fm = fm.clone();
863 } catch (CloneNotSupportedException e1) {
864 log.error("Failure cloning flow mod", e1);
865 }
866 }
867 }
868
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200869 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200870 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200871 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
872
873 DataPath path = topoRouteService.getShortestPath(
874 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
875
876 if (path == null){
877 log.debug("Unable to compute path for BGP traffic for {}",
878 bgpPeer.getIpAddress());
879 continue;
880 }
881
882 //Set up the flow mod
883 OFFlowMod fm =
884 (OFFlowMod) floodlightProvider.getOFMessageFactory()
885 .getMessage(OFType.FLOW_MOD);
886
887 OFActionOutput action = new OFActionOutput();
888 action.setMaxLength((short)0xffff);
889 List<OFAction> actions = new ArrayList<OFAction>();
890 actions.add(action);
891
892 fm.setIdleTimeout((short)0)
893 .setHardTimeout((short)0)
894 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
895 .setCookie(BGP_COOKIE)
896 .setCommand(OFFlowMod.OFPFC_ADD)
897 .setPriority(SDNIP_PRIORITY)
898 .setActions(actions)
899 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
900
901 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
902 OFMatch forwardMatchSrc = new OFMatch();
903
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200904 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
905 + "/32";
906 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
907 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200908
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200909 //Common match fields
910 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
911 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
912 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
913 forwardMatchSrc.setTransportDestination(BGP_PORT);
914 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
915 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
916
917
918 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
919
920 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
921 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
922
923 OFMatch forwardMatchDst = forwardMatchSrc.clone();
924
925 forwardMatchSrc.setTransportSource(BGP_PORT);
926 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
927 forwardMatchDst.setTransportDestination(BGP_PORT);
928 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
929
930 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
931 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
932
933 OFMatch reverseMatchDst = reverseMatchSrc.clone();
934
935 reverseMatchSrc.setTransportSource(BGP_PORT);
936 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
937 reverseMatchDst.setTransportDestination(BGP_PORT);
938 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
939
940 fm.setMatch(forwardMatchSrc);
941
Jonathan Hart38c84932013-08-10 17:49:27 +1200942 OFMatch forwardIcmpMatch = new OFMatch();
943 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
944 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
945 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
946 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
947
948 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
949 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
950 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
951
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200952 for (FlowEntry flowEntry : path.flowEntries()){
953 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
954 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200955 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200956 try {
957 forwardFlowModSrc = fm.clone();
958 forwardFlowModDst = fm.clone();
959 reverseFlowModSrc = fm.clone();
960 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200961 forwardIcmp = fm.clone();
962 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200963 } catch (CloneNotSupportedException e) {
964 log.warn("Clone failed", e);
965 continue;
966 }
967
968 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
969 forwardFlowModSrc.setMatch(forwardMatchSrc);
970 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
971 .setPort(flowEntry.outPort().value());
972
973 forwardMatchDst.setInputPort(flowEntry.inPort().value());
974 forwardFlowModDst.setMatch(forwardMatchDst);
975 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
976 .setPort(flowEntry.outPort().value());
977
978 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
979 reverseFlowModSrc.setMatch(reverseMatchSrc);
980 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
981 .setPort(flowEntry.inPort().value());
982
983 reverseMatchDst.setInputPort(flowEntry.outPort().value());
984 reverseFlowModDst.setMatch(reverseMatchDst);
985 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
986 .setPort(flowEntry.inPort().value());
987
Jonathan Hart38c84932013-08-10 17:49:27 +1200988 ((OFActionOutput)forwardIcmp.getActions().get(0))
989 .setPort(flowEntry.outPort().value());
990 forwardIcmp.setMatch(forwardIcmpMatch);
991
992 ((OFActionOutput)reverseIcmp.getActions().get(0))
993 .setPort(flowEntry.inPort().value());
994 reverseIcmp.setMatch(reverseIcmpMatch);
995
996
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200997 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
998
Jonathan Hart38c84932013-08-10 17:49:27 +1200999 if (sw == null) {
1000 log.warn("Switch not found when pushing BGP paths");
1001 return;
1002 }
1003
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001004 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
1005 msgList.add(forwardFlowModSrc);
1006 msgList.add(forwardFlowModDst);
1007 msgList.add(reverseFlowModSrc);
1008 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +12001009 msgList.add(forwardIcmp);
1010 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001011
1012 try {
1013 sw.write(msgList, null);
1014 sw.flush();
1015 } catch (IOException e) {
1016 log.error("Failure writing flow mod", e);
1017 }
1018 }
1019 }
1020 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001021
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001022 @Override
1023 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
1024 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
1025 MACAddress.valueOf(macAddress).toString());
1026
1027 Set<PathUpdate> pathsToPush = pathsWaitingOnArp.removeAll(ipAddress);
1028
1029 for (PathUpdate update : pathsToPush) {
1030 log.debug("Pushing path to {} at {} on {}", new Object[] {
1031 update.getDstIpAddress().getHostAddress(),
1032 MACAddress.valueOf(macAddress),
1033 update.getDstInterface().getSwitchPort()});
1034 calculateAndPushPath(update.getDstInterface(),
1035 MACAddress.valueOf(macAddress));
1036 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001037
1038 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
1039
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001040 /*
1041 * We synchronize on this to prevent changes to the ptree while we're pushing
1042 * flows to the switches. If the ptree changes, the ptree and switches
1043 * could get out of sync.
1044 */
1045 synchronized (this) {
1046 for (RibUpdate update : prefixesToPush) {
1047 //These will always be adds
1048
1049 //addPrefixFlows(update.getPrefix(), update.getRibEntry());
1050 //processRibAdd(update);
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001051 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001052 if (rib != null && rib.equals(update.getRibEntry())) {
1053 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001054 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001055 //We only push prefix flows if the prefix is still in the ptree
1056 //and the next hop is the same as our update. The prefix could
1057 //have been removed while we were waiting for the ARP, or the
1058 //next hop could have changed.
1059 addPrefixFlows(update.getPrefix(), rib);
1060 } else {
1061 log.debug("Received ARP response, but {},{} is no longer in ptree",
1062 update.getPrefix(), update.getRibEntry());
1063 }
1064 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001065 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001066 }
1067
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001068 private void beginRouting(){
1069 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001070 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001071 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001072
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001073 //Traverse ptree and create flows for all routes
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001074 /*
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001075 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
1076 if (node.rib != null){
1077 prefixAdded(node);
1078 }
1079 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001080 */
1081
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001082 /*
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001083 synchronized (ptree) {
1084 Iterator<IPatriciaTrie.Entry> it = ptree.iterator();
1085 while (it.hasNext()) {
1086 IPatriciaTrie.Entry entry = it.next();
1087 addPrefixFlows(entry.getPrefix(), entry.getRib());
1088 }
1089 }
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001090 */
1091
1092 bgpUpdatesExecutor.execute(new Runnable() {
1093 @Override
1094 public void run() {
1095 doUpdatesThread();
1096 }
1097 });
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001098
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001099 }
1100
1101 private void checkSwitchesConnected(){
1102 for (String dpid : switches){
1103 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1104 log.debug("Not all switches are here yet");
1105 return;
1106 }
1107 }
1108 switchesConnected = true;
1109 }
1110
Jonathan Hartc824ad02013-07-03 15:58:45 +12001111 //Actually we only need to go half way round to verify full mesh connectivity
1112 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001113 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001114 for (Interface dstInterface : interfaces.values()) {
1115 for (Interface srcInterface : interfaces.values()) {
1116 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001117 continue;
1118 }
1119
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001120 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001121 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001122
1123 if (shortestPath == null){
1124 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001125 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001126 return;
1127 }
1128 }
1129 }
1130 topologyReady = true;
1131 }
1132
1133 private void checkStatus(){
1134 log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
1135
1136 if (!switchesConnected){
1137 checkSwitchesConnected();
1138 }
1139 boolean oldTopologyReadyStatus = topologyReady;
1140 if (switchesConnected && !topologyReady){
1141 checkTopologyReady();
1142 }
1143 if (!oldTopologyReadyStatus && topologyReady){
1144 beginRouting();
1145 }
1146 }
1147
pingping-lina2cbfad2013-03-07 08:39:21 +08001148 @Override
1149 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +08001150 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001151 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -07001152 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +08001153
Jonathan Hartc7ca35d2013-06-25 20:54:25 +12001154 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
1155
Jonathan Hart61ba9372013-05-19 20:10:29 -07001156 //Retrieve the RIB from BGPd during startup
1157 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +08001158 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001159
1160 private void doUpdatesThread() {
1161 boolean interrupted = false;
1162 try {
1163 while (true) {
1164 try {
1165 RibUpdate update = ribUpdates.take();
1166 switch (update.getOperation()){
1167 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001168 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001169 break;
1170 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001171 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001172 break;
1173 }
1174 } catch (InterruptedException e) {
Jonathan Hart9ea31212013-08-12 21:40:34 +12001175 log.debug("interrupted", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001176 interrupted = true;
1177 }
1178 }
1179 } finally {
1180 if (interrupted) {
1181 Thread.currentThread().interrupt();
1182 }
1183 }
1184 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001185
1186 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001187 public void topologyChanged() {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001188 boolean refreshNeeded = false;
1189 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1190 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1191 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001192 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001193 refreshNeeded = true;
1194 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001195
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001196 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001197
Jonathan Hart98957bf2013-07-01 14:49:24 +12001198 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1199 synchronized (linkUpdates) {
1200 linkUpdates.add(ldu);
1201 }
1202 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001203 }
1204
1205 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001206 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001207 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001208 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001209
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001210 //TODO determine whether we need to listen for switch joins
1211 @Override
1212 public void addedSwitch(IOFSwitch sw) {
1213 //checkStatus();
1214 }
1215
1216 @Override
1217 public void removedSwitch(IOFSwitch sw) {
1218 // TODO Auto-generated method stub
1219 }
1220
1221 @Override
1222 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001223
1224 @Override
1225 public String getName() {
1226 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +08001227 }
1228}