blob: bbc9f150ca80b2af31e959ae58ac10b9348e0d94 [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 Hart309889c2013-08-13 23:26:24 +120074import com.google.common.net.InetAddresses;
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;
Jonathan Hart29b972d2013-08-12 23:43:51 +120092 protected IPatriciaTrie<RibEntry> ptree;
Jonathan Hartabf10222013-08-13 10:19:34 +120093 protected IPatriciaTrie<Interface> interfacePtrie;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120094 protected BlockingQueue<RibUpdate> ribUpdates;
95
Jonathan Hart61ba9372013-05-19 20:10:29 -070096 protected String bgpdRestIp;
97 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120098 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070099
100 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
101 //the controller/OS should hand out cookie IDs to prevent conflicts.
102 protected final long APP_COOKIE = 0xa0000000000000L;
103 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
104 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
105 //Cookie for flows in ingress switches that rewrite the MAC address
106 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200107 //Cookie for flows that setup BGP paths
108 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200109 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
110 //need to be higher priority than this otherwise the rewrite may not get done
111 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700112
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200113 protected final short BGP_PORT = 179;
114
Jonathan Hart98957bf2013-07-01 14:49:24 +1200115 protected final int TOPO_DETECTION_WAIT = 2; //seconds
116
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200117 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200118 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200119 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200120 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200121 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200122
123 //True when all switches have connected
124 protected volatile boolean switchesConnected = false;
125 //True when we have a full mesh of shortest paths between gateways
126 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200127
Jonathan Hart98957bf2013-07-01 14:49:24 +1200128 protected ArrayList<LDUpdate> linkUpdates;
129 protected SingletonTask topologyChangeDetectorTask;
130
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200131 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200132
133 //TODO should this really be a Multimap?
134 //Es kann nur einen geben per IP address?
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200135 protected SetMultimap<InetAddress, PathUpdate> pathsWaitingOnArp;
136
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200137 protected ExecutorService bgpUpdatesExecutor;
138
Jonathan Hart309889c2013-08-13 23:26:24 +1200139 protected Map<InetAddress, PathUpdate> pushedPaths;
140 protected Map<Prefix, PathUpdate> prefixToPath;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200141 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200142
Jonathan Hart98957bf2013-07-01 14:49:24 +1200143 protected class TopologyChangeDetector implements Runnable {
144 @Override
145 public void run() {
146 log.debug("Running topology change detection task");
147 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200148 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200149 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
150
151 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200152
153 Iterator<LDUpdate> it = linkUpdates.iterator();
154 while (it.hasNext()){
155 LDUpdate ldu = it.next();
156 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
157 ldu.getDst(), ldu.getDstPort());
158
159 if (activeLinks.contains(l)){
160 log.debug("Not found: {}", l);
161 it.remove();
162 }
163 }
164 }
165
166 if (linkUpdates.isEmpty()){
167 //All updates have been seen in network map.
168 //We can check if topology is ready
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200169 log.debug("No known changes outstanding. Checking topology now");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200170 checkStatus();
171 }
172 else {
173 //We know of some link updates that haven't propagated to the database yet
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200174 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200175 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
176 }
177 }
178 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700179
Jonathan Hartd1f23252013-06-13 15:17:05 +1200180 private void readGatewaysConfiguration(String gatewaysFilename){
181 File gatewaysFile = new File(gatewaysFilename);
182 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700183
Jonathan Hartd1f23252013-06-13 15:17:05 +1200184 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200185 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
186
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200187 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200188 interfaces = new HashMap<String, Interface>();
189 for (Interface intf : config.getInterfaces()){
190 interfaces.put(intf.getName(), intf);
191 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200192 bgpPeers = new HashMap<InetAddress, BgpPeer>();
193 for (BgpPeer peer : config.getPeers()){
194 bgpPeers.put(peer.getIpAddress(), peer);
195 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200196
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200197 bgpdAttachmentPoint = new SwitchPort(
198 new Dpid(config.getBgpdAttachmentDpid()),
199 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200200
Jonathan Hartd1f23252013-06-13 15:17:05 +1200201 } catch (JsonParseException e) {
202 log.error("Error in JSON file", e);
203 System.exit(1);
204 } catch (JsonMappingException e) {
205 log.error("Error in JSON file", e);
206 System.exit(1);
207 } catch (IOException e) {
208 log.error("Error reading JSON file", e);
209 System.exit(1);
210 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200211
212 //Populate the interface Patricia Trie
213 for (Interface intf : interfaces.values()) {
214 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
215 interfacePtrie.put(prefix, intf);
216 }
217
218 /*
219 Iterator<IPatriciaTrie.Entry<Interface>> it = interfacePtrie.iterator();
220 while (it.hasNext()) {
221 IPatriciaTrie.Entry<Interface> entry = it.next();
222 Interface intf = entry.getValue();
223 log.debug("Interface at prefix {}, switchport {}/{}",
224 new Object[] {entry.getPrefix(), HexString.toHexString(intf.getDpid()), intf.getPort()});
225 }
226 */
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700227 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800228
229 @Override
230 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700231 Collection<Class<? extends IFloodlightService>> l
232 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800233 l.add(IBgpRouteService.class);
234 return l;
235 }
236
237 @Override
238 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700239 Map<Class<? extends IFloodlightService>, IFloodlightService> m
240 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800241 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800242 return m;
243 }
244
pingping-lina2cbfad2013-03-07 08:39:21 +0800245 @Override
246 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700247 Collection<Class<? extends IFloodlightService>> l
248 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800249 l.add(IFloodlightProviderService.class);
250 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700251 l.add(IDeviceService.class);
252 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800253 return l;
254 }
255
256 @Override
257 public void init(FloodlightModuleContext context)
258 throws FloodlightModuleException {
259
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200260 //ptree = new Ptree(32);
Jonathan Hart29b972d2013-08-12 23:43:51 +1200261 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200262 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200263
264 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200265
pingping-lina2cbfad2013-03-07 08:39:21 +0800266 // Register floodlight provider and REST handler.
267 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800268 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700269 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200270 restApi = context.getServiceImpl(IRestApiService.class);
271
272 //TODO We'll initialise this here for now, but it should really be done as
273 //part of the controller core
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200274 proxyArp = new ProxyArpManager(floodlightProvider, topology, devices);
pingping-lina2cbfad2013-03-07 08:39:21 +0800275
Jonathan Hart98957bf2013-07-01 14:49:24 +1200276 linkUpdates = new ArrayList<LDUpdate>();
277 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
278 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700279
280 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200281
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200282 pathsWaitingOnArp = Multimaps.synchronizedSetMultimap(
283 HashMultimap.<InetAddress, PathUpdate>create());
284 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
285 HashMultimap.<InetAddress, RibUpdate>create());
286
Jonathan Hart309889c2013-08-13 23:26:24 +1200287 pushedPaths = new HashMap<InetAddress, PathUpdate>();
288 prefixToPath = new HashMap<Prefix, PathUpdate>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200289 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
290
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200291 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
292 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
293
Jonathan Hart61ba9372013-05-19 20:10:29 -0700294 //Read in config values
295 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
296 if (bgpdRestIp == null){
297 log.error("BgpdRestIp property not found in config file");
298 System.exit(1);
299 }
300 else {
301 log.info("BgpdRestIp set to {}", bgpdRestIp);
302 }
303
304 routerId = context.getConfigParams(this).get("RouterId");
305 if (routerId == null){
306 log.error("RouterId property not found in config file");
307 System.exit(1);
308 }
309 else {
310 log.info("RouterId set to {}", routerId);
311 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200312
Jonathan Hart9575cb62013-07-05 13:43:49 +1200313 String configFilenameParameter = context.getConfigParams(this).get("configfile");
314 if (configFilenameParameter != null){
315 configFilename = configFilenameParameter;
316 }
317 log.debug("Config file set to {}", configFilename);
318
319 readGatewaysConfiguration(configFilename);
pingping-lina2cbfad2013-03-07 08:39:21 +0800320 // Test.
321 //test();
322 }
323
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200324 //public Ptree getPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200325 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800326 return ptree;
327 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700328
329 public void clearPtree() {
330 //ptree = null;
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200331 //ptree = new Ptree(32);
Jonathan Hart29b972d2013-08-12 23:43:51 +1200332 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800333 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700334
pingping-line2a09ca2013-03-23 09:33:58 +0800335 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700336 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800337 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700338
pingping-line2a09ca2013-03-23 09:33:58 +0800339 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700340 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800341 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800342
343 // Return nexthop address as byte array.
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200344 /*
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200345 public RibEntry lookupRib(byte[] dest) {
pingping-lina2cbfad2013-03-07 08:39:21 +0800346 if (ptree == null) {
347 log.debug("lookupRib: ptree null");
348 return null;
349 }
350
351 PtreeNode node = ptree.match(dest, 32);
352 if (node == null) {
353 log.debug("lookupRib: ptree node null");
354 return null;
355 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700356
pingping-lina2cbfad2013-03-07 08:39:21 +0800357 if (node.rib == null) {
358 log.debug("lookupRib: ptree rib null");
359 return null;
360 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700361
pingping-lina2cbfad2013-03-07 08:39:21 +0800362 ptree.delReference(node);
363
364 return node.rib;
365 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200366 */
pingping-lina2cbfad2013-03-07 08:39:21 +0800367
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200368 /*
Jonathan Hart61ba9372013-05-19 20:10:29 -0700369 //TODO looks like this should be a unit test
pingping-lina2cbfad2013-03-07 08:39:21 +0800370 @SuppressWarnings("unused")
Jonathan Hart61ba9372013-05-19 20:10:29 -0700371 private void test() throws UnknownHostException {
pingping-lina2cbfad2013-03-07 08:39:21 +0800372 System.out.println("Here it is");
373 Prefix p = new Prefix("128.0.0.0", 8);
374 Prefix q = new Prefix("8.0.0.0", 8);
375 Prefix r = new Prefix("10.0.0.0", 24);
376 Prefix a = new Prefix("10.0.0.1", 32);
377
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200378 ptree.acquire(p.getAddress(), p.getPrefixLength());
379 ptree.acquire(q.getAddress(), q.getPrefixLength());
380 ptree.acquire(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800381
382 System.out.println("Traverse start");
383 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
384 Prefix p_result = new Prefix(node.key, node.keyBits);
385 }
386
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200387 PtreeNode n = ptree.match(a.getAddress(), a.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800388 if (n != null) {
389 System.out.println("Matched prefix for 10.0.0.1:");
390 Prefix x = new Prefix(n.key, n.keyBits);
391 ptree.delReference(n);
392 }
393
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200394 n = ptree.lookup(p.getAddress(), p.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800395 if (n != null) {
396 ptree.delReference(n);
397 ptree.delReference(n);
398 }
399 System.out.println("Traverse start");
400 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
401 Prefix p_result = new Prefix(node.key, node.keyBits);
402 }
403
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200404 n = ptree.lookup(q.getAddress(), q.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800405 if (n != null) {
406 ptree.delReference(n);
407 ptree.delReference(n);
408 }
409 System.out.println("Traverse start");
410 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
411 Prefix p_result = new Prefix(node.key, node.keyBits);
412 }
413
Jonathan Hartd1b9d872013-07-23 12:17:21 +1200414 n = ptree.lookup(r.getAddress(), r.getPrefixLength());
pingping-lina2cbfad2013-03-07 08:39:21 +0800415 if (n != null) {
416 ptree.delReference(n);
417 ptree.delReference(n);
418 }
419 System.out.println("Traverse start");
420 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)) {
421 Prefix p_result = new Prefix(node.key, node.keyBits);
422 }
423
424 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200425 */
pingping-lina2cbfad2013-03-07 08:39:21 +0800426
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200427 //TODO once the Ptree is object oriented this can go
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200428 /*
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200429 private String getPrefixFromPtree(PtreeNode node){
430 InetAddress address = null;
431 try {
432 address = InetAddress.getByAddress(node.key);
433 } catch (UnknownHostException e1) {
434 //Should never happen is the reverse conversion has already been done
435 log.error("Malformed IP address");
436 return "";
437 }
438 return address.toString() + "/" + node.rib.masklen;
439 }
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200440 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200441
Jonathan Hart61ba9372013-05-19 20:10:29 -0700442 private void retrieveRib(){
443 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
444 String response = RestClient.get(url);
445
446 if (response.equals("")){
447 return;
448 }
449
450 response = response.replaceAll("\"", "'");
451 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
452 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
453 String router_id = jsonObj.getString("router-id");
454
455 int size = rib_json_array.size();
456
457 log.info("Retrived RIB of {} entries from BGPd", size);
458
459 for (int j = 0; j < size; j++) {
460 JSONObject second_json_object = rib_json_array.getJSONObject(j);
461 String prefix = second_json_object.getString("prefix");
462 String nexthop = second_json_object.getString("nexthop");
463
464 //insert each rib entry into the local rib;
465 String[] substring = prefix.split("/");
466 String prefix1 = substring[0];
467 String mask1 = substring[1];
468
469 Prefix p;
470 try {
471 p = new Prefix(prefix1, Integer.valueOf(mask1));
472 } catch (NumberFormatException e) {
473 log.warn("Wrong mask format in RIB JSON: {}", mask1);
474 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200475 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700476 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
477 continue;
478 }
479
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200480 //PtreeNode node = ptree.acquire(p.getAddress(), p.getPrefixLength());
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200481 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700482
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200483 /*
Jonathan Hart61ba9372013-05-19 20:10:29 -0700484 if (node.rib != null) {
485 node.rib = null;
486 ptree.delReference(node);
487 }
488
489 node.rib = rib;
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200490 */
491
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200492 //ptree.put(p, rib);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700493
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200494 //addPrefixFlows(p, rib);
495 try {
496 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
497 } catch (InterruptedException e) {
498 log.debug("Interrupted while pushing onto update queue");
499 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700500 }
501 }
502
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200503 @Override
504 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200505 try {
506 ribUpdates.put(update);
507 } catch (InterruptedException e) {
508 // TODO Auto-generated catch block
509 log.debug(" ", e);
510 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200511 }
512
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200513 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200514 Prefix prefix = update.getPrefix();
515
Jonathan Hart9ea31212013-08-12 21:40:34 +1200516 log.debug("Processing prefix add {}", prefix);
517
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200518 //PtreeNode node = ptree.acquire(prefix.getAddress(), prefix.getPrefixLength());
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200519 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200520
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200521 //if (node.rib != null) {
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200522 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200523 //There was an existing nexthop for this prefix. This update supersedes that,
524 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200525 //deletePrefixFlows(prefix);
526 _processDeletePrefix(prefix, rib);
Jonathan Hart2f740782013-08-04 00:49:21 +1200527
528 //Then remove the old nexthop from the Ptree
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200529 //node.rib = null;
530 //ptree.delReference(node);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200531 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200532
533 //Put the new nexthop in the Ptree
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200534 //node.rib = update.getRibEntry();
Jonathan Hart309889c2013-08-13 23:26:24 +1200535
536 //log.debug("hurro {}", InetAddresses.forString("0.0.0.0").getHostAddress());
537 //InetAddresses.forString("0.0.0.0").getHostAddress()});//, rib.getNextHop().equals(InetAddresses.forString("0.0.0.0"))});
538 if (update.getRibEntry().getNextHop().equals(InetAddresses.forString("0.0.0.0"))) {
539 //Route originated by SDN domain
540 //We don't handle these at the moment
541 log.debug("Own route {} to {}", prefix, update.getRibEntry().getNextHop().getHostAddress());
542 return;
543 }
544
545 _processRibAdd(update);
546
Jonathan Hart2f740782013-08-04 00:49:21 +1200547 //Push flows for the new <prefix, nexthop>
Jonathan Hart309889c2013-08-13 23:26:24 +1200548 //addPrefixFlows(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200549 }
550
Jonathan Hart309889c2013-08-13 23:26:24 +1200551 private void _processRibAdd(RibUpdate update) {
552 Prefix prefix = update.getPrefix();
553 RibEntry rib = update.getRibEntry();
554
555 InetAddress dstIpAddress = rib.getNextHop();
556
557 byte[] nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
558 //Interface egressInterface = null;
559 Interface egressInterface = null;//getEgressInterface(prefix, rib.getNextHop());
560
561 if (bgpPeers.containsKey(dstIpAddress)) {
562 //Route to a peer
563 log.debug("Route to peer {}", dstIpAddress);
564 BgpPeer peer = bgpPeers.get(dstIpAddress);
565 egressInterface = interfaces.get(peer.getInterfaceName());
566
567 /*
568 if (nextHopMacAddress == null) {
569 //A RibUpdate is still a nice way to package them up
570 prefixesWaitingOnArp.put(rib.getNextHop(),
571 new RibUpdate(Operation.UPDATE, prefix, rib));
572 proxyArp.sendArpRequest(rib.getNextHop(), this, true);
573 return;
574 }
575 else {
576 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
577 }
578 */
579 }
580 else {
581 //Route to someone else
582 log.debug("Route to non-peer {}", dstIpAddress);
583 egressInterface = interfacePtrie.match(
584 new Prefix(dstIpAddress.getAddress(), 32));
585 if (egressInterface == null) {
586 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
587 return;
588 }
589 /*
590 if (nextHopMacAddress == null) {
591 //A RibUpdate is still a nice way to package them up
592 prefixesWaitingOnArp.put(rib.getNextHop(),
593 new RibUpdate(Operation.UPDATE, prefix, rib));
594 //pathsWaitingOnArp.put(rib.getNextHop(),
595 // new PathUpdate(egressInterface, rib.getNextHop()));
596
597 proxyArp.sendArpRequest(rib.getNextHop(), this, true);
598 return;
599 }
600 else {
601 //calculateAndPushPath(egressInterface, new MACAddress(nextHopMacAddress));
602 setUpDataPath(egressInterface, rib.getNextHop(), MACAddress.valueOf(nextHopMacAddress));
603 //installPathToNextHop(egressInterface, rib.getNextHop());
604 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
605 }*/
606 }
607
608 if (nextHopMacAddress == null) {
609 prefixesWaitingOnArp.put(dstIpAddress,
610 new RibUpdate(Operation.UPDATE, prefix, rib));
611 proxyArp.sendArpRequest(dstIpAddress, this, true);
612 return;
613 }
614 else {
615 if (!bgpPeers.containsKey(dstIpAddress)) {
616 //setUpDataPath(new PathUpdate(egressInterface, dstIpAddress),
617 //PathUpdate path = new PathUpdate(egressInterface, dstIpAddress);
618 PathUpdate path = pushedPaths.get(dstIpAddress);
619 if (path == null) {
620 path = new PathUpdate(egressInterface, dstIpAddress);
621 pushedPaths.put(dstIpAddress, path);
622 }
623 //PathUpdate path = setUpDataPath(egressInterface, dstIpAddress,
624 // MACAddress.valueOf(nextHopMacAddress));
625 setUpDataPath(path, MACAddress.valueOf(nextHopMacAddress));
626
627 path.incrementUsers();
628 prefixToPath.put(prefix, path);
629 }
630 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
631 }
632 }
633
634 /*
635 private Interface getEgressInterface(Prefix prefix, InetAddress nextHop) {
636 if (bgpPeers.containsKey(nextHop)) {
637 //Route to a peer
638 log.debug("Route to peer {}", nextHop);
639 BgpPeer peer = bgpPeers.get(nextHop);
640 return interfaces.get(peer.getInterfaceName());
641 }
642 else {
643 //Route to someone else
644 log.debug("Route to non-peer {}", nextHop);
645 return interfacePtrie.match(prefix);
646 }
647 }
648 */
649
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200650 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200651 Prefix prefix = update.getPrefix();
652
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200653 //PtreeNode node = ptree.lookup(prefix.getAddress(), prefix.getPrefixLength());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200654
655 /*
656 * Remove the flows from the switches before the rib is lost
657 * Theory: we could get a delete for a prefix not in the Ptree.
658 * This would result in a null node being returned. We could get a delete for
659 * a node that's not actually there, but is a aggregate node. This would result
660 * in a non-null node with a null rib. Only a non-null node with a non-null
661 * rib is an actual prefix in the Ptree.
662 */
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200663
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200664 /*
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200665 if (node != null && node.rib != null) {
666 if (update.getRibEntry().equals(node.rib)) {
667 node.rib = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200668 ptree.delReference(node);
669
Jonathan Hart2f740782013-08-04 00:49:21 +1200670 deletePrefixFlows(update.getPrefix());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200671 }
672 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200673 */
674
675 if (ptree.remove(prefix, update.getRibEntry())) {
676 /*
677 * Only delete flows if an entry was actually removed from the trie.
678 * If no entry was removed, the <prefix, nexthop> wasn't there so
679 * it's probably already been removed and we don't need to do anything
680 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200681 _processDeletePrefix(prefix, update.getRibEntry());
682
683 //TODO may need to delete a path here too
684 }
685 }
686
687 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
688 deletePrefixFlows(prefix);
689
690 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
691 log.debug("is peer {}", bgpPeers.containsKey(ribEntry.getNextHop()));
692 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
693 log.debug("Getting path for route with non-peer nexthop");
694 PathUpdate path = prefixToPath.get(prefix);
695
696 if (path == null) {
697 log.error("No path found for non-peer path");
698 }
699
700 path.decrementUsers();
701 log.debug("users {}, permanent {}", path.getUsers(), path.isPermanent());
702 if (path.getUsers() <= 0 && !path.isPermanent()) {
703 deletePath(path);
704 }
705 }
706 }
707
708 private void deletePath(PathUpdate path) {
709 for (PushedFlowMod pfm : path.getFlowMods()) {
710 log.debug("Pushing a DELETE flow mod to {}, dst MAC {}",
711 new Object[] {HexString.toHexString(pfm.getDpid()),
712 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
713 });
714
715 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
716 }
717 }
718
719 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
720 addFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
721 .setOutPort(OFPort.OFPP_NONE)
722 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
723
724 addFlowMod.getActions().clear();
725
726 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
727 if (sw == null) {
728 log.warn("Switch not found when pushing delete flow mod");
729 return;
730 }
731
732 try {
733 sw.write(addFlowMod, null);
734 sw.flush();
735 } catch (IOException e) {
736 log.error("Failure writing flow mod", e);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200737 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200738 }
739
Jonathan Hart2f740782013-08-04 00:49:21 +1200740 //TODO compatibility layer, used by beginRouting()
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200741 /*public void prefixAdded(PtreeNode node) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200742 Prefix prefix = null;
743 try {
744 prefix = new Prefix(node.key, node.rib.masklen);
Jonathan Hart32e18222013-08-07 22:05:42 +1200745 } catch (IllegalArgumentException e) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200746 log.error(" ", e);
747 }
Jonathan Hartdf6ec332013-08-04 01:37:14 +1200748
Jonathan Hart2f740782013-08-04 00:49:21 +1200749 addPrefixFlows(prefix, node.rib);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200750 }*/
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200751
Jonathan Hart309889c2013-08-13 23:26:24 +1200752 private void addPrefixFlows(Prefix prefix, Interface egressInterface, byte[] nextHopMacAddress) {
753 //TODO get rid of this
754 /*if (!topologyReady){
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200755 return;
Jonathan Hart309889c2013-08-13 23:26:24 +1200756 }*/
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200757
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200758 //TODO before we do anything, we have to check that the RIB entry is still in the
759 //Ptree because it could have been removed while we were waiting for ARP.
760 //I think we'll have to make prefixAdded and prefixDelete atomic as well
761 //to protect against the prefix getting deleted while where trying to add it
Jonathan Hart2f740782013-08-04 00:49:21 +1200762
Jonathan Hart309889c2013-08-13 23:26:24 +1200763 log.debug("Adding flows for prefix {} added, next hop mac {}",
764 prefix, HexString.toHexString(nextHopMacAddress));
765 //prefix, rib.getNextHop().getHostAddress());
766
767
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200768
Jonathan Hartc824ad02013-07-03 15:58:45 +1200769 //TODO this is wrong, we shouldn't be dealing with BGP peers here.
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200770 //We need to figure out where the device is attached and what its
Jonathan Hartc824ad02013-07-03 15:58:45 +1200771 //mac address is by learning.
772 //The next hop is not necessarily the peer, and the peer's attachment
773 //point is not necessarily the next hop's attachment point.
Jonathan Hart309889c2013-08-13 23:26:24 +1200774
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700775
Jonathan Hart309889c2013-08-13 23:26:24 +1200776
777 //if (peer == null){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200778 //TODO local router isn't in peers list so this will get thrown
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200779 //Need to work out what to do about local prefixes with next hop 0.0.0.0.
Jonathan Hartc824ad02013-07-03 15:58:45 +1200780
781 //The other scenario is this is a route server route. In that
782 //case the next hop is not in our configuration
Jonathan Hart309889c2013-08-13 23:26:24 +1200783 //log.error("Couldn't find next hop router in router {} in config",
784 // rib.getNextHop().getHostAddress());
785 //return; //just quit out here? This is probably a configuration error
786 //}
Jonathan Hartc824ad02013-07-03 15:58:45 +1200787
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200788 //Get MAC address for peer from the ARP module
789 //TODO separate out the 'ask for MAC' bit to another method
Jonathan Hart309889c2013-08-13 23:26:24 +1200790 //byte[] peerMacAddress = proxyArp.getMacAddress(peer.getIpAddress());
791 //byte[] nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
792 //if (nextHopMacAddress == null) {
793
794 //}
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200795
Jonathan Hart309889c2013-08-13 23:26:24 +1200796 //Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200797
Jonathan Hartc824ad02013-07-03 15:58:45 +1200798 //Add a flow to rewrite mac for this prefix to all border switches
799 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200800 if (srcInterface == egressInterface) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200801 //Don't push a flow for the switch where this peer is attached
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700802 continue;
803 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200804
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700805 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +1200806 srcInterface.getSwitchPort(),
Jonathan Hart309889c2013-08-13 23:26:24 +1200807 egressInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700808
809 if (shortestPath == null){
810 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +1200811 srcInterface.getSwitchPort(),
Jonathan Hart309889c2013-08-13 23:26:24 +1200812 egressInterface.getSwitchPort());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700813 return; // just quit here?
814 }
815
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700816 //Set up the flow mod
817 OFFlowMod fm =
818 (OFFlowMod) floodlightProvider.getOFMessageFactory()
819 .getMessage(OFType.FLOW_MOD);
820
821 fm.setIdleTimeout((short)0)
822 .setHardTimeout((short)0)
823 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
824 .setCookie(MAC_RW_COOKIE)
825 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200826 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700827 .setLengthU(OFFlowMod.MINIMUM_LENGTH
828 + OFActionDataLayerDestination.MINIMUM_LENGTH
829 + OFActionOutput.MINIMUM_LENGTH);
830
831 OFMatch match = new OFMatch();
832 match.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200833 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700834
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200835 /*
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200836 InetAddress address = null;
837 try {
Jonathan Hart2f740782013-08-04 00:49:21 +1200838 address = InetAddress.getByAddress(prefix.getAddress());
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200839 } catch (UnknownHostException e1) {
840 //Should never happen is the reverse conversion has already been done
841 log.error("Malformed IP address");
842 return;
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200843 }*/
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200844
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200845 //match.setFromCIDR(address.getHostAddress() + "/" +
846 // prefix.getPrefixLength(), OFMatch.STR_NW_DST);
847 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200848 fm.setMatch(match);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700849
850 //Set up MAC rewrite action
851 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200852 //TODO the peer's mac address is not necessarily the next hop's...
Jonathan Hart309889c2013-08-13 23:26:24 +1200853 macRewriteAction.setDataLayerAddress(nextHopMacAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700854
855 //Set up output action
856 OFActionOutput outputAction = new OFActionOutput();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200857 outputAction.setMaxLength((short)0xffff);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700858
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200859 Port outputPort = shortestPath.flowEntries().get(0).outPort();
860 outputAction.setPort(outputPort.value());
861
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700862 List<OFAction> actions = new ArrayList<OFAction>();
863 actions.add(macRewriteAction);
864 actions.add(outputAction);
865 fm.setActions(actions);
866
867 //Write to switch
868 IOFSwitch sw = floodlightProvider.getSwitches()
Jonathan Hartc824ad02013-07-03 15:58:45 +1200869 .get(srcInterface.getDpid());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700870
871 if (sw == null){
872 log.warn("Switch not found when pushing flow mod");
873 continue;
874 }
875
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200876 //TODO if prefix Added/Deleted are synchronized this shouldn't have to be
Jonathan Hart2f740782013-08-04 00:49:21 +1200877 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200878
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700879 List<OFMessage> msglist = new ArrayList<OFMessage>();
880 msglist.add(fm);
881 try {
882 sw.write(msglist, null);
883 sw.flush();
884 } catch (IOException e) {
885 log.error("Failure writing flow mod", e);
886 }
887 }
888 }
889
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200890 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200891 //TODO check delete/add synchronization
Jonathan Hart2f740782013-08-04 00:49:21 +1200892
893 private void deletePrefixFlows(Prefix prefix) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200894 /*if (!topologyReady) {
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200895 return;
Jonathan Hart309889c2013-08-13 23:26:24 +1200896 }*/
897
Jonathan Hart2f740782013-08-04 00:49:21 +1200898 /*for (Map.Entry<Prefix, PushedFlowMod> entry : pushedFlows.entries()) {
899 log.debug("Pushed flow: {} => {}", entry.getKey(), entry.getValue());
900 }*/
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200901
902 Collection<PushedFlowMod> pushedFlowMods
Jonathan Hart2f740782013-08-04 00:49:21 +1200903 = pushedFlows.removeAll(prefix);
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200904
905 for (PushedFlowMod pfm : pushedFlowMods) {
906 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
907 new Object[] {HexString.toHexString(pfm.getDpid()),
908 pfm.getFlowMod().getMatch().getNetworkDestination() +
909 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
910 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
911 .getDataLayerAddress())});
912
Jonathan Hart309889c2013-08-13 23:26:24 +1200913 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
914 /*
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200915 OFFlowMod fm = pfm.getFlowMod();
916
917 fm.setCommand(OFFlowMod.OFPFC_DELETE)
Jonathan Hart2f740782013-08-04 00:49:21 +1200918 .setOutPort(OFPort.OFPP_NONE)
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200919 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
920
921 fm.getActions().clear();
922
923 IOFSwitch sw = floodlightProvider.getSwitches().get(pfm.getDpid());
924 if (sw == null) {
925 log.warn("Switch not found when pushing delete flow mod");
926 continue;
927 }
928
929 try {
930 sw.write(fm, null);
931 sw.flush();
932 } catch (IOException e) {
933 log.error("Failure writing flow mod", e);
934 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200935 */
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200936 }
937 }
938
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700939 /*
940 * On startup we need to calculate a full mesh of paths between all gateway
941 * switches
942 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200943 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700944 //For each border router, calculate and install a path from every other
945 //border switch to said border router. However, don't install the entry
946 //in to the first hop switch, as we need to install an entry to rewrite
947 //for each prefix received. This will be done later when prefixes have
948 //actually been received.
949
Jonathan Hartc824ad02013-07-03 15:58:45 +1200950 for (BgpPeer peer : bgpPeers.values()) {
951 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200952
Jonathan Hart309889c2013-08-13 23:26:24 +1200953 //We know there's not already a Path here pushed, because this is
954 //called before all other routing
955 PathUpdate path = new PathUpdate(peerInterface, peer.getIpAddress());
956 path.setPermanent();
957
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200958 //See if we know the MAC address of the peer. If not we can't
959 //do anything until we learn it
960 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
961 if (mac == null) {
962 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
963 //Put in the pending paths list first
964 pathsWaitingOnArp.put(peer.getIpAddress(),
Jonathan Hart309889c2013-08-13 23:26:24 +1200965 //new PathUpdate(peerInterface, peer.getIpAddress()));
966 path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700967
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200968 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
969 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700970 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200971
972 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200973 //calculateAndPushPath(peerInterface, MACAddress.valueOf(mac));
974 //setUpDataPath(peerInterface, peer.getIpAddress(), MACAddress.valueOf(mac));
975 setUpDataPath(path, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700976 }
977 }
978
Jonathan Hart309889c2013-08-13 23:26:24 +1200979 //private void setUpDataPath(Interface dstInterface, InetAddress dstInetAddress,
980 //private PathUpdate setUpDataPath(Interface dstInterface, InetAddress dstInetAddress, MACAddress dstMacAddress) {
981 private void setUpDataPath(PathUpdate path, MACAddress dstMacAddress) {
982 //PathUpdate path = pushedPaths.get(dstInterface);
983
984
985 //if (!pushedPaths.containsKey(path.getDstIpAddress())) {
986 //if (path == null) {
987 //PathUpdate path = new PathUpdate(dstInterface, dstInetAddress);
988 //path = new PathUpdate(dstInterface, dstInetAddress);
989 calculateAndPushPath(path, dstMacAddress);
990 //pushedPaths.put(path.getDstIpAddress(), path);
991 //calculateAndPushPath(dstInterface, dstMacAddress);
992 //pushedPaths.put(dstInetAddress, new PathUpdate(dstInterface, dstInetAddress));
993 //}
994
995 //return path;
996
997 /*
998 else {
999 existingPath.incrementUsers();
1000 }
1001 */
1002 }
1003
1004 //private void calculateAndPushPath(Interface dstInterface, MACAddress dstMacAddress) {
1005 private void calculateAndPushPath(PathUpdate path, MACAddress dstMacAddress) {
1006 Interface dstInterface = path.getDstInterface();
1007
1008 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
1009
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001010 for (Interface srcInterface : interfaces.values()) {
1011 if (dstInterface.equals(srcInterface.getName())){
1012 continue;
1013 }
1014
1015 DataPath shortestPath = topoRouteService.getShortestPath(
1016 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1017
1018 if (shortestPath == null){
1019 log.debug("Shortest path between {} and {} not found",
1020 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1021 return; // just quit here?
1022 }
1023
Jonathan Hart309889c2013-08-13 23:26:24 +12001024 //List<PushedFlowMod> pushedFlows
1025 // = installPath(shortestPath.flowEntries(), dstMacAddress);
1026 pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001027 }
Jonathan Hart309889c2013-08-13 23:26:24 +12001028
1029 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001030 }
1031
Jonathan Hart309889c2013-08-13 23:26:24 +12001032 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
1033 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
1034
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07001035 //Set up the flow mod
1036 OFFlowMod fm =
1037 (OFFlowMod) floodlightProvider.getOFMessageFactory()
1038 .getMessage(OFType.FLOW_MOD);
1039
1040 OFActionOutput action = new OFActionOutput();
1041 action.setMaxLength((short)0xffff);
1042 List<OFAction> actions = new ArrayList<OFAction>();
1043 actions.add(action);
1044
1045 fm.setIdleTimeout((short)0)
1046 .setHardTimeout((short)0)
1047 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1048 .setCookie(L2_FWD_COOKIE)
1049 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07001050 .setActions(actions)
1051 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1052
1053 //Don't push the first flow entry. We need to push entries in the
1054 //first switch based on IP prefix which we don't know yet.
1055 for (int i = 1; i < flowEntries.size(); i++){
1056 FlowEntry flowEntry = flowEntries.get(i);
1057
1058 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001059 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07001060 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1061 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
1062
1063 fm.setMatch(match);
1064
1065 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
1066
1067 if (sw == null){
1068 log.warn("Switch not found when pushing flow mod");
1069 continue;
1070 }
1071
Jonathan Hart309889c2013-08-13 23:26:24 +12001072 flowMods.add(new PushedFlowMod(sw.getId(), fm));
1073
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07001074 List<OFMessage> msglist = new ArrayList<OFMessage>();
1075 msglist.add(fm);
1076 try {
1077 sw.write(msglist, null);
1078 sw.flush();
1079 } catch (IOException e) {
1080 log.error("Failure writing flow mod", e);
1081 }
1082
1083 try {
1084 fm = fm.clone();
1085 } catch (CloneNotSupportedException e1) {
1086 log.error("Failure cloning flow mod", e1);
1087 }
1088 }
Jonathan Hart309889c2013-08-13 23:26:24 +12001089
1090 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07001091 }
1092
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001093 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001094 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001095 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
1096
1097 DataPath path = topoRouteService.getShortestPath(
1098 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
1099
1100 if (path == null){
1101 log.debug("Unable to compute path for BGP traffic for {}",
1102 bgpPeer.getIpAddress());
1103 continue;
1104 }
1105
1106 //Set up the flow mod
1107 OFFlowMod fm =
1108 (OFFlowMod) floodlightProvider.getOFMessageFactory()
1109 .getMessage(OFType.FLOW_MOD);
1110
1111 OFActionOutput action = new OFActionOutput();
1112 action.setMaxLength((short)0xffff);
1113 List<OFAction> actions = new ArrayList<OFAction>();
1114 actions.add(action);
1115
1116 fm.setIdleTimeout((short)0)
1117 .setHardTimeout((short)0)
1118 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1119 .setCookie(BGP_COOKIE)
1120 .setCommand(OFFlowMod.OFPFC_ADD)
1121 .setPriority(SDNIP_PRIORITY)
1122 .setActions(actions)
1123 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1124
1125 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
1126 OFMatch forwardMatchSrc = new OFMatch();
1127
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001128 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
1129 + "/32";
1130 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
1131 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +12001132
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001133 //Common match fields
1134 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
1135 //forwardMatch.setWildcards(forwardMatch.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1136 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
1137 forwardMatchSrc.setTransportDestination(BGP_PORT);
1138 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
1139 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
1140
1141
1142 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
1143
1144 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
1145 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
1146
1147 OFMatch forwardMatchDst = forwardMatchSrc.clone();
1148
1149 forwardMatchSrc.setTransportSource(BGP_PORT);
1150 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1151 forwardMatchDst.setTransportDestination(BGP_PORT);
1152 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
1153
1154 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
1155 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
1156
1157 OFMatch reverseMatchDst = reverseMatchSrc.clone();
1158
1159 reverseMatchSrc.setTransportSource(BGP_PORT);
1160 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1161 reverseMatchDst.setTransportDestination(BGP_PORT);
1162 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
1163
1164 fm.setMatch(forwardMatchSrc);
1165
Jonathan Hart38c84932013-08-10 17:49:27 +12001166 OFMatch forwardIcmpMatch = new OFMatch();
1167 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
1168 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
1169 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
1170 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
1171
1172 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
1173 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
1174 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
1175
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001176 for (FlowEntry flowEntry : path.flowEntries()){
1177 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
1178 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +12001179 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001180 try {
1181 forwardFlowModSrc = fm.clone();
1182 forwardFlowModDst = fm.clone();
1183 reverseFlowModSrc = fm.clone();
1184 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +12001185 forwardIcmp = fm.clone();
1186 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001187 } catch (CloneNotSupportedException e) {
1188 log.warn("Clone failed", e);
1189 continue;
1190 }
1191
1192 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
1193 forwardFlowModSrc.setMatch(forwardMatchSrc);
1194 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
1195 .setPort(flowEntry.outPort().value());
1196
1197 forwardMatchDst.setInputPort(flowEntry.inPort().value());
1198 forwardFlowModDst.setMatch(forwardMatchDst);
1199 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
1200 .setPort(flowEntry.outPort().value());
1201
1202 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
1203 reverseFlowModSrc.setMatch(reverseMatchSrc);
1204 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
1205 .setPort(flowEntry.inPort().value());
1206
1207 reverseMatchDst.setInputPort(flowEntry.outPort().value());
1208 reverseFlowModDst.setMatch(reverseMatchDst);
1209 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
1210 .setPort(flowEntry.inPort().value());
1211
Jonathan Hart38c84932013-08-10 17:49:27 +12001212 ((OFActionOutput)forwardIcmp.getActions().get(0))
1213 .setPort(flowEntry.outPort().value());
1214 forwardIcmp.setMatch(forwardIcmpMatch);
1215
1216 ((OFActionOutput)reverseIcmp.getActions().get(0))
1217 .setPort(flowEntry.inPort().value());
1218 reverseIcmp.setMatch(reverseIcmpMatch);
1219
1220
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001221 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
1222
Jonathan Hart38c84932013-08-10 17:49:27 +12001223 if (sw == null) {
1224 log.warn("Switch not found when pushing BGP paths");
1225 return;
1226 }
1227
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001228 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
1229 msgList.add(forwardFlowModSrc);
1230 msgList.add(forwardFlowModDst);
1231 msgList.add(reverseFlowModSrc);
1232 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +12001233 msgList.add(forwardIcmp);
1234 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001235
1236 try {
1237 sw.write(msgList, null);
1238 sw.flush();
1239 } catch (IOException e) {
1240 log.error("Failure writing flow mod", e);
1241 }
1242 }
1243 }
1244 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001245
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001246 @Override
1247 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
1248 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
1249 MACAddress.valueOf(macAddress).toString());
1250
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001251 /*
1252 * We synchronize on this to prevent changes to the ptree while we're pushing
1253 * flows to the switches. If the ptree changes, the ptree and switches
1254 * could get out of sync.
1255 */
1256 synchronized (this) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001257 Set<PathUpdate> pathsToPush = pathsWaitingOnArp.removeAll(ipAddress);
1258
1259 for (PathUpdate update : pathsToPush) {
1260 log.debug("Pushing path to {} at {} on {}", new Object[] {
1261 update.getDstIpAddress().getHostAddress(),
1262 MACAddress.valueOf(macAddress),
1263 update.getDstInterface().getSwitchPort()});
1264 //calculateAndPushPath(update.getDstInterface(),
1265 //MACAddress.valueOf(macAddress));
1266 //setUpDataPath(update.getDstInterface(), update.getDstIpAddress(),
1267 if (pushedPaths.containsKey(update.getDstInterface())) {
1268 //A path already got pushed to this endpoint while we were waiting
1269 //for ARP. We'll copy over the permanent attribute if it is set on this path.
1270 if (update.isPermanent()) {
1271 pushedPaths.get(update.getDstInterface()).setPermanent();
1272 }
1273 }
1274 else {
1275 setUpDataPath(update, MACAddress.valueOf(macAddress));
1276 pushedPaths.put(update.getDstIpAddress(), update);
1277 }
1278 }
1279
1280
1281
1282 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
1283
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001284 for (RibUpdate update : prefixesToPush) {
1285 //These will always be adds
1286
1287 //addPrefixFlows(update.getPrefix(), update.getRibEntry());
1288 //processRibAdd(update);
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001289 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001290 if (rib != null && rib.equals(update.getRibEntry())) {
1291 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001292 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001293 //We only push prefix flows if the prefix is still in the ptree
1294 //and the next hop is the same as our update. The prefix could
1295 //have been removed while we were waiting for the ARP, or the
1296 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +12001297 //addPrefixFlows(update.getPrefix(), rib);
1298 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001299 } else {
1300 log.debug("Received ARP response, but {},{} is no longer in ptree",
1301 update.getPrefix(), update.getRibEntry());
1302 }
1303 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001304 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001305 }
1306
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001307 private void beginRouting(){
1308 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001309 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001310 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001311
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001312 //Traverse ptree and create flows for all routes
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001313 /*
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001314 for (PtreeNode node = ptree.begin(); node != null; node = ptree.next(node)){
1315 if (node.rib != null){
1316 prefixAdded(node);
1317 }
1318 }
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001319 */
1320
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001321 /*
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001322 synchronized (ptree) {
1323 Iterator<IPatriciaTrie.Entry> it = ptree.iterator();
1324 while (it.hasNext()) {
1325 IPatriciaTrie.Entry entry = it.next();
1326 addPrefixFlows(entry.getPrefix(), entry.getRib());
1327 }
1328 }
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001329 */
1330
1331 bgpUpdatesExecutor.execute(new Runnable() {
1332 @Override
1333 public void run() {
1334 doUpdatesThread();
1335 }
1336 });
Jonathan Hartd7e158d2013-08-07 23:04:48 +12001337
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001338 }
1339
1340 private void checkSwitchesConnected(){
1341 for (String dpid : switches){
1342 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1343 log.debug("Not all switches are here yet");
1344 return;
1345 }
1346 }
1347 switchesConnected = true;
1348 }
1349
Jonathan Hartc824ad02013-07-03 15:58:45 +12001350 //Actually we only need to go half way round to verify full mesh connectivity
1351 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001352 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001353 for (Interface dstInterface : interfaces.values()) {
1354 for (Interface srcInterface : interfaces.values()) {
1355 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001356 continue;
1357 }
1358
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001359 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001360 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001361
1362 if (shortestPath == null){
1363 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001364 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001365 return;
1366 }
1367 }
1368 }
1369 topologyReady = true;
1370 }
1371
1372 private void checkStatus(){
Jonathan Hart309889c2013-08-13 23:26:24 +12001373 //log.debug("In checkStatus, swC {}, toRe {}", switchesConnected, topologyReady);
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001374
1375 if (!switchesConnected){
1376 checkSwitchesConnected();
1377 }
1378 boolean oldTopologyReadyStatus = topologyReady;
1379 if (switchesConnected && !topologyReady){
1380 checkTopologyReady();
1381 }
1382 if (!oldTopologyReadyStatus && topologyReady){
1383 beginRouting();
1384 }
1385 }
1386
pingping-lina2cbfad2013-03-07 08:39:21 +08001387 @Override
1388 public void startUp(FloodlightModuleContext context) {
pingping-line2a09ca2013-03-23 09:33:58 +08001389 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001390 floodlightProvider.addOFSwitchListener(this);
Jonathan Hart61ba9372013-05-19 20:10:29 -07001391 topology.addListener(this);
pingping-line2a09ca2013-03-23 09:33:58 +08001392
Jonathan Hartc7ca35d2013-06-25 20:54:25 +12001393 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
1394
Jonathan Hart61ba9372013-05-19 20:10:29 -07001395 //Retrieve the RIB from BGPd during startup
1396 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +08001397 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001398
1399 private void doUpdatesThread() {
1400 boolean interrupted = false;
1401 try {
1402 while (true) {
1403 try {
1404 RibUpdate update = ribUpdates.take();
1405 switch (update.getOperation()){
1406 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001407 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001408 break;
1409 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001410 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001411 break;
1412 }
1413 } catch (InterruptedException e) {
Jonathan Hart9ea31212013-08-12 21:40:34 +12001414 log.debug("interrupted", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001415 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001416 } catch (Exception e) {
1417 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001418 }
1419 }
1420 } finally {
1421 if (interrupted) {
1422 Thread.currentThread().interrupt();
1423 }
1424 }
1425 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001426
1427 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001428 public void topologyChanged() {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001429 boolean refreshNeeded = false;
1430 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1431 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1432 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001433 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001434 refreshNeeded = true;
1435 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001436
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001437 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001438
Jonathan Hart98957bf2013-07-01 14:49:24 +12001439 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1440 synchronized (linkUpdates) {
1441 linkUpdates.add(ldu);
1442 }
1443 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001444 }
1445
1446 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001447 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001448 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001449 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001450
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001451 //TODO determine whether we need to listen for switch joins
1452 @Override
1453 public void addedSwitch(IOFSwitch sw) {
1454 //checkStatus();
1455 }
1456
1457 @Override
1458 public void removedSwitch(IOFSwitch sw) {
1459 // TODO Auto-generated method stub
1460 }
1461
1462 @Override
1463 public void switchPortChanged(Long switchId) {}
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001464
1465 @Override
1466 public String getName() {
1467 return "BgpRoute";
pingping-lina2cbfad2013-03-07 08:39:21 +08001468 }
1469}