blob: 9bc00930f2eadf2d5239c2722e31b9950ee821b1 [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 Hart64c0b202013-08-20 15:45:07 +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.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120029import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080030import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120031import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080032import net.floodlightcontroller.topology.ITopologyListener;
33import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120034import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120035import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
Jonathan Hart98957bf2013-07-01 14:49:24 +120036import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070037import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120038import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070039import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
40import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120041import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120042import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070043import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070044import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120045import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070046import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.Port;
48import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080049import net.sf.json.JSONArray;
50import net.sf.json.JSONObject;
51import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080052
Jonathan Hartd1f23252013-06-13 15:17:05 +120053import org.codehaus.jackson.JsonParseException;
54import org.codehaus.jackson.map.JsonMappingException;
55import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070056import org.openflow.protocol.OFFlowMod;
57import org.openflow.protocol.OFMatch;
58import org.openflow.protocol.OFMessage;
59import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120060import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070061import org.openflow.protocol.OFType;
62import org.openflow.protocol.action.OFAction;
63import org.openflow.protocol.action.OFActionDataLayerDestination;
64import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120065import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080066import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
Jonathan Hart4dfc3652013-08-02 20:22:36 +120069import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120070import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120071import com.google.common.collect.Multimaps;
72import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120073import com.google.common.net.InetAddresses;
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 Hart64c0b202013-08-20 15:45:07 +120077 ITopologyListener, IArpRequester,
78 IOFSwitchListener {
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;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070085 protected IRestApiService restApi;
86
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120087 protected ProxyArpManager proxyArp;
88
Jonathan Hart29b972d2013-08-12 23:43:51 +120089 protected IPatriciaTrie<RibEntry> ptree;
Jonathan Hartabf10222013-08-13 10:19:34 +120090 protected IPatriciaTrie<Interface> interfacePtrie;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120091 protected BlockingQueue<RibUpdate> ribUpdates;
92
Jonathan Hart61ba9372013-05-19 20:10:29 -070093 protected String bgpdRestIp;
94 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120095 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070096
97 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
98 //the controller/OS should hand out cookie IDs to prevent conflicts.
99 protected final long APP_COOKIE = 0xa0000000000000L;
100 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
101 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
102 //Cookie for flows in ingress switches that rewrite the MAC address
103 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200104 //Cookie for flows that setup BGP paths
105 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200106 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
107 //need to be higher priority than this otherwise the rewrite may not get done
108 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700109
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200110 protected final short BGP_PORT = 179;
111
Jonathan Hart98957bf2013-07-01 14:49:24 +1200112 protected final int TOPO_DETECTION_WAIT = 2; //seconds
113
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200114 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200115 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200116 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200117 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200118 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart2f790d22013-08-15 14:01:24 +1200119 protected MACAddress bgpdMacAddress;
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;
Jonathan Hart309889c2013-08-13 23:26:24 +1200130
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200131 protected Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200132
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200133 protected ExecutorService bgpUpdatesExecutor;
134
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200135 protected Map<InetAddress, Path> pushedPaths;
136 protected Map<Prefix, Path> prefixToPath;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200137 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200138
139 protected volatile Map<Long, ?> topoRouteTopology = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200140
Jonathan Hart98957bf2013-07-01 14:49:24 +1200141 protected class TopologyChangeDetector implements Runnable {
142 @Override
143 public void run() {
144 log.debug("Running topology change detection task");
145 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200146 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200147 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
148
149 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200150
151 Iterator<LDUpdate> it = linkUpdates.iterator();
152 while (it.hasNext()){
153 LDUpdate ldu = it.next();
154 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
155 ldu.getDst(), ldu.getDstPort());
156
157 if (activeLinks.contains(l)){
158 log.debug("Not found: {}", l);
159 it.remove();
160 }
161 }
162 }
163
Jonathan Hart64c0b202013-08-20 15:45:07 +1200164 if (!topologyReady) {
165 if (linkUpdates.isEmpty()){
166 //All updates have been seen in network map.
167 //We can check if topology is ready
168 log.debug("No known changes outstanding. Checking topology now");
169 checkStatus();
170 }
171 else {
172 //We know of some link updates that haven't propagated to the database yet
173 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
174 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
175 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200176 }
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 Hart2f790d22013-08-15 14:01:24 +1200201 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200202 } catch (JsonParseException e) {
203 log.error("Error in JSON file", e);
204 System.exit(1);
205 } catch (JsonMappingException e) {
206 log.error("Error in JSON file", e);
207 System.exit(1);
208 } catch (IOException e) {
209 log.error("Error reading JSON file", e);
210 System.exit(1);
211 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200212
213 //Populate the interface Patricia Trie
214 for (Interface intf : interfaces.values()) {
215 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
216 interfacePtrie.put(prefix, intf);
217 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700218 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800219
220 @Override
221 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700222 Collection<Class<? extends IFloodlightService>> l
223 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800224 l.add(IBgpRouteService.class);
225 return l;
226 }
227
228 @Override
229 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700230 Map<Class<? extends IFloodlightService>, IFloodlightService> m
231 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800232 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800233 return m;
234 }
235
pingping-lina2cbfad2013-03-07 08:39:21 +0800236 @Override
237 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700238 Collection<Class<? extends IFloodlightService>> l
239 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800240 l.add(IFloodlightProviderService.class);
241 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700242 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800243 return l;
244 }
245
246 @Override
247 public void init(FloodlightModuleContext context)
248 throws FloodlightModuleException {
249
Jonathan Hart29b972d2013-08-12 23:43:51 +1200250 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200251 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200252
253 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200254
pingping-lina2cbfad2013-03-07 08:39:21 +0800255 // Register floodlight provider and REST handler.
256 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800257 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200258 restApi = context.getServiceImpl(IRestApiService.class);
259
260 //TODO We'll initialise this here for now, but it should really be done as
261 //part of the controller core
Jonathan Hart2f790d22013-08-15 14:01:24 +1200262 proxyArp = new ProxyArpManager(floodlightProvider, topology);
pingping-lina2cbfad2013-03-07 08:39:21 +0800263
Jonathan Hart98957bf2013-07-01 14:49:24 +1200264 linkUpdates = new ArrayList<LDUpdate>();
265 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
266 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700267
268 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200269
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200270 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200271 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
272 HashMultimap.<InetAddress, RibUpdate>create());
273
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200274 pushedPaths = new HashMap<InetAddress, Path>();
275 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200276 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
277
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200278 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
279 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
280
Jonathan Hart61ba9372013-05-19 20:10:29 -0700281 //Read in config values
282 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
283 if (bgpdRestIp == null){
284 log.error("BgpdRestIp property not found in config file");
285 System.exit(1);
286 }
287 else {
288 log.info("BgpdRestIp set to {}", bgpdRestIp);
289 }
290
291 routerId = context.getConfigParams(this).get("RouterId");
292 if (routerId == null){
293 log.error("RouterId property not found in config file");
294 System.exit(1);
295 }
296 else {
297 log.info("RouterId set to {}", routerId);
298 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200299
Jonathan Hart9575cb62013-07-05 13:43:49 +1200300 String configFilenameParameter = context.getConfigParams(this).get("configfile");
301 if (configFilenameParameter != null){
302 configFilename = configFilenameParameter;
303 }
304 log.debug("Config file set to {}", configFilename);
305
306 readGatewaysConfiguration(configFilename);
Jonathan Hart2f790d22013-08-15 14:01:24 +1200307
308 proxyArp.setL3Mode(interfacePtrie, bgpdMacAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200309 }
310
311 @Override
312 public void startUp(FloodlightModuleContext context) {
313 restApi.addRestletRoutable(new BgpRouteWebRoutable());
314 topology.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200315 floodlightProvider.addOFSwitchListener(this);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200316
Jonathan Hart2f790d22013-08-15 14:01:24 +1200317 proxyArp.startUp();
318
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200319 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
320
321 //Retrieve the RIB from BGPd during startup
322 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800323 }
324
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() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200330 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800331 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700332
pingping-line2a09ca2013-03-23 09:33:58 +0800333 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700334 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800335 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700336
pingping-line2a09ca2013-03-23 09:33:58 +0800337 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700338 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800339 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800340
Jonathan Hart61ba9372013-05-19 20:10:29 -0700341 private void retrieveRib(){
342 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
343 String response = RestClient.get(url);
344
345 if (response.equals("")){
346 return;
347 }
348
349 response = response.replaceAll("\"", "'");
350 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
351 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
352 String router_id = jsonObj.getString("router-id");
353
354 int size = rib_json_array.size();
355
356 log.info("Retrived RIB of {} entries from BGPd", size);
357
358 for (int j = 0; j < size; j++) {
359 JSONObject second_json_object = rib_json_array.getJSONObject(j);
360 String prefix = second_json_object.getString("prefix");
361 String nexthop = second_json_object.getString("nexthop");
362
363 //insert each rib entry into the local rib;
364 String[] substring = prefix.split("/");
365 String prefix1 = substring[0];
366 String mask1 = substring[1];
367
368 Prefix p;
369 try {
370 p = new Prefix(prefix1, Integer.valueOf(mask1));
371 } catch (NumberFormatException e) {
372 log.warn("Wrong mask format in RIB JSON: {}", mask1);
373 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200374 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700375 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
376 continue;
377 }
378
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200379 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200380
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200381 try {
382 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
383 } catch (InterruptedException e) {
384 log.debug("Interrupted while pushing onto update queue");
385 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700386 }
387 }
388
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200389 @Override
390 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200391 try {
392 ribUpdates.put(update);
393 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200394 log.debug("Interrupted while putting on ribUpdates queue", e);
395 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200396 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200397 }
398
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200399 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200400 Prefix prefix = update.getPrefix();
401
Jonathan Hart9ea31212013-08-12 21:40:34 +1200402 log.debug("Processing prefix add {}", prefix);
403
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200404 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200405
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200406 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200407 //There was an existing nexthop for this prefix. This update supersedes that,
408 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200409 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200410 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200411
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200412 if (update.getRibEntry().getNextHop().equals(
413 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200414 //Route originated by SDN domain
415 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200416 log.debug("Own route {} to {}", prefix,
417 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200418 return;
419 }
420
421 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200422 }
423
Jonathan Hart309889c2013-08-13 23:26:24 +1200424 private void _processRibAdd(RibUpdate update) {
425 Prefix prefix = update.getPrefix();
426 RibEntry rib = update.getRibEntry();
427
428 InetAddress dstIpAddress = rib.getNextHop();
429
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200430 //See if we know the MAC address of the next hop
Jonathan Hart309889c2013-08-13 23:26:24 +1200431 byte[] nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200432
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200433 //Find the attachment point (egress interface) of the next hop
434 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200435 if (bgpPeers.containsKey(dstIpAddress)) {
436 //Route to a peer
437 log.debug("Route to peer {}", dstIpAddress);
438 BgpPeer peer = bgpPeers.get(dstIpAddress);
439 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200440 }
441 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200442 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200443 log.debug("Route to non-peer {}", dstIpAddress);
444 egressInterface = interfacePtrie.match(
445 new Prefix(dstIpAddress.getAddress(), 32));
446 if (egressInterface == null) {
447 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
448 return;
449 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200450 }
451
452 if (nextHopMacAddress == null) {
453 prefixesWaitingOnArp.put(dstIpAddress,
454 new RibUpdate(Operation.UPDATE, prefix, rib));
455 proxyArp.sendArpRequest(dstIpAddress, this, true);
456 return;
457 }
458 else {
459 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200460 //If the prefix is for a non-peer we need to ensure there's a path,
461 //and push one if there isn't.
462 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200463 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200464 path = new Path(egressInterface, dstIpAddress);
465 setUpDataPath(path, MACAddress.valueOf(nextHopMacAddress));
Jonathan Hart309889c2013-08-13 23:26:24 +1200466 pushedPaths.put(dstIpAddress, path);
467 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200468
469 path.incrementUsers();
470 prefixToPath.put(prefix, path);
471 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200472
473 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200474 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
475 }
476 }
477
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200478 private void addPrefixFlows(Prefix prefix, Interface egressInterface, byte[] nextHopMacAddress) {
479 log.debug("Adding flows for prefix {} added, next hop mac {}",
480 prefix, HexString.toHexString(nextHopMacAddress));
481
482 //Add a flow to rewrite mac for this prefix to all other border switches
483 for (Interface srcInterface : interfaces.values()) {
484 if (srcInterface == egressInterface) {
485 //Don't push a flow for the switch where this peer is attached
486 continue;
487 }
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200488
489
490 DataPath shortestPath;
491 if (topoRouteTopology == null) {
492 shortestPath = topoRouteService.getShortestPath(
493 srcInterface.getSwitchPort(),
494 egressInterface.getSwitchPort());
495 }
496 else {
497 shortestPath = topoRouteService.getTopoShortestPath(
498 topoRouteTopology, srcInterface.getSwitchPort(),
499 egressInterface.getSwitchPort());
500 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200501
502 if (shortestPath == null){
503 log.debug("Shortest path between {} and {} not found",
504 srcInterface.getSwitchPort(),
505 egressInterface.getSwitchPort());
506 return; // just quit here?
507 }
508
509 //Set up the flow mod
510 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
511 .getMessage(OFType.FLOW_MOD);
512
513 fm.setIdleTimeout((short)0)
514 .setHardTimeout((short)0)
515 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
516 .setCookie(MAC_RW_COOKIE)
517 .setCommand(OFFlowMod.OFPFC_ADD)
518 .setPriority(SDNIP_PRIORITY)
519 .setLengthU(OFFlowMod.MINIMUM_LENGTH
520 + OFActionDataLayerDestination.MINIMUM_LENGTH
521 + OFActionOutput.MINIMUM_LENGTH);
522
523 OFMatch match = new OFMatch();
524 match.setDataLayerType(Ethernet.TYPE_IPv4);
525 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
526
527 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
528 fm.setMatch(match);
529
530 //Set up MAC rewrite action
531 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
532 macRewriteAction.setDataLayerAddress(nextHopMacAddress);
533
534 //Set up output action
535 OFActionOutput outputAction = new OFActionOutput();
536 outputAction.setMaxLength((short)0xffff);
537 Port outputPort = shortestPath.flowEntries().get(0).outPort();
538 outputAction.setPort(outputPort.value());
539
540 List<OFAction> actions = new ArrayList<OFAction>();
541 actions.add(macRewriteAction);
542 actions.add(outputAction);
543 fm.setActions(actions);
544
545 //Write to switch
546 IOFSwitch sw = floodlightProvider.getSwitches()
547 .get(srcInterface.getDpid());
548
549 if (sw == null){
550 log.warn("Switch not found when pushing flow mod");
551 continue;
552 }
553
554 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
555
556 List<OFMessage> msglist = new ArrayList<OFMessage>();
557 msglist.add(fm);
558 try {
559 sw.write(msglist, null);
560 sw.flush();
561 } catch (IOException e) {
562 log.error("Failure writing flow mod", e);
563 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200564 }
565 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200566
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200567 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200568 Prefix prefix = update.getPrefix();
569
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200570 if (ptree.remove(prefix, update.getRibEntry())) {
571 /*
572 * Only delete flows if an entry was actually removed from the trie.
573 * If no entry was removed, the <prefix, nexthop> wasn't there so
574 * it's probably already been removed and we don't need to do anything
575 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200576 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200577 }
578 }
579
580 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
581 deletePrefixFlows(prefix);
582
583 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
584 log.debug("is peer {}", bgpPeers.containsKey(ribEntry.getNextHop()));
585 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
586 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200587 //Path path = prefixToPath.get(prefix);
588 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200589
590 if (path == null) {
591 log.error("No path found for non-peer path");
592 }
593
594 path.decrementUsers();
595 log.debug("users {}, permanent {}", path.getUsers(), path.isPermanent());
596 if (path.getUsers() <= 0 && !path.isPermanent()) {
597 deletePath(path);
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200598 pushedPaths.remove(path.getDstIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200599 }
600 }
601 }
602
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200603 private void deletePrefixFlows(Prefix prefix) {
604 Collection<PushedFlowMod> pushedFlowMods
605 = pushedFlows.removeAll(prefix);
606
607 for (PushedFlowMod pfm : pushedFlowMods) {
608 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
609 new Object[] {HexString.toHexString(pfm.getDpid()),
610 pfm.getFlowMod().getMatch().getNetworkDestination() +
611 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
612 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
613 .getDataLayerAddress())});
614
615 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
616 }
617 }
618
619 private void deletePath(Path path) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200620 for (PushedFlowMod pfm : path.getFlowMods()) {
621 log.debug("Pushing a DELETE flow mod to {}, dst MAC {}",
622 new Object[] {HexString.toHexString(pfm.getDpid()),
623 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
624 });
625
626 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
627 }
628 }
629
630 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
631 addFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
632 .setOutPort(OFPort.OFPP_NONE)
633 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
634
635 addFlowMod.getActions().clear();
636
637 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
638 if (sw == null) {
639 log.warn("Switch not found when pushing delete flow mod");
640 return;
641 }
642
643 try {
644 sw.write(addFlowMod, null);
645 sw.flush();
646 } catch (IOException e) {
647 log.error("Failure writing flow mod", e);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200648 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200649 }
650
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200651 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200652 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200653
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700654 /*
655 * On startup we need to calculate a full mesh of paths between all gateway
656 * switches
657 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200658 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700659 //For each border router, calculate and install a path from every other
660 //border switch to said border router. However, don't install the entry
661 //in to the first hop switch, as we need to install an entry to rewrite
662 //for each prefix received. This will be done later when prefixes have
663 //actually been received.
664
Jonathan Hartc824ad02013-07-03 15:58:45 +1200665 for (BgpPeer peer : bgpPeers.values()) {
666 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200667
Jonathan Hart309889c2013-08-13 23:26:24 +1200668 //We know there's not already a Path here pushed, because this is
669 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200670 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200671 path.setPermanent();
672
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200673 //See if we know the MAC address of the peer. If not we can't
674 //do anything until we learn it
675 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
676 if (mac == null) {
677 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
678 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200679 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700680
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200681 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
682 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700683 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200684
685 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200686 setUpDataPath(path, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700687 }
688 }
689
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200690 private void setUpDataPath(Path path, MACAddress dstMacAddress) {
691 calculateAndPushPath(path, dstMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200692 }
693
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200694 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200695 Interface dstInterface = path.getDstInterface();
696
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200697 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
698 dstMacAddress);
699
Jonathan Hart309889c2013-08-13 23:26:24 +1200700 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
701
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200702 for (Interface srcInterface : interfaces.values()) {
703 if (dstInterface.equals(srcInterface.getName())){
704 continue;
705 }
706
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200707 DataPath shortestPath;
708 if (topoRouteTopology == null) {
709 log.debug("Using database topo");
710 shortestPath = topoRouteService.getShortestPath(
711 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
712 }
713 else {
714 log.debug("Using prepared topo");
715 shortestPath = topoRouteService.getTopoShortestPath(topoRouteTopology,
716 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
717 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200718
719 if (shortestPath == null){
720 log.debug("Shortest path between {} and {} not found",
721 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
722 return; // just quit here?
723 }
724
Jonathan Hart309889c2013-08-13 23:26:24 +1200725 pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200726 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200727
728 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200729 }
730
Jonathan Hart309889c2013-08-13 23:26:24 +1200731 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
732 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
733
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700734 //Set up the flow mod
735 OFFlowMod fm =
736 (OFFlowMod) floodlightProvider.getOFMessageFactory()
737 .getMessage(OFType.FLOW_MOD);
738
739 OFActionOutput action = new OFActionOutput();
740 action.setMaxLength((short)0xffff);
741 List<OFAction> actions = new ArrayList<OFAction>();
742 actions.add(action);
743
744 fm.setIdleTimeout((short)0)
745 .setHardTimeout((short)0)
746 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
747 .setCookie(L2_FWD_COOKIE)
748 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700749 .setActions(actions)
750 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
751
752 //Don't push the first flow entry. We need to push entries in the
753 //first switch based on IP prefix which we don't know yet.
754 for (int i = 1; i < flowEntries.size(); i++){
755 FlowEntry flowEntry = flowEntries.get(i);
756
757 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200758 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700759 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
760 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
761
762 fm.setMatch(match);
763
764 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
765
766 if (sw == null){
767 log.warn("Switch not found when pushing flow mod");
768 continue;
769 }
770
Jonathan Hart309889c2013-08-13 23:26:24 +1200771 flowMods.add(new PushedFlowMod(sw.getId(), fm));
772
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700773 List<OFMessage> msglist = new ArrayList<OFMessage>();
774 msglist.add(fm);
775 try {
776 sw.write(msglist, null);
777 sw.flush();
778 } catch (IOException e) {
779 log.error("Failure writing flow mod", e);
780 }
781
782 try {
783 fm = fm.clone();
784 } catch (CloneNotSupportedException e1) {
785 log.error("Failure cloning flow mod", e1);
786 }
787 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200788
789 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700790 }
791
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200792 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200793 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200794 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
795
796 DataPath path = topoRouteService.getShortestPath(
797 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
798
799 if (path == null){
800 log.debug("Unable to compute path for BGP traffic for {}",
801 bgpPeer.getIpAddress());
802 continue;
803 }
804
805 //Set up the flow mod
806 OFFlowMod fm =
807 (OFFlowMod) floodlightProvider.getOFMessageFactory()
808 .getMessage(OFType.FLOW_MOD);
809
810 OFActionOutput action = new OFActionOutput();
811 action.setMaxLength((short)0xffff);
812 List<OFAction> actions = new ArrayList<OFAction>();
813 actions.add(action);
814
815 fm.setIdleTimeout((short)0)
816 .setHardTimeout((short)0)
817 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
818 .setCookie(BGP_COOKIE)
819 .setCommand(OFFlowMod.OFPFC_ADD)
820 .setPriority(SDNIP_PRIORITY)
821 .setActions(actions)
822 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
823
824 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
825 OFMatch forwardMatchSrc = new OFMatch();
826
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200827 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
828 + "/32";
829 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
830 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200831
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200832 //Common match fields
833 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200834 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
835 forwardMatchSrc.setTransportDestination(BGP_PORT);
836 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
837 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
838
839
840 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
841
842 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
843 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
844
845 OFMatch forwardMatchDst = forwardMatchSrc.clone();
846
847 forwardMatchSrc.setTransportSource(BGP_PORT);
848 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
849 forwardMatchDst.setTransportDestination(BGP_PORT);
850 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
851
852 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
853 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
854
855 OFMatch reverseMatchDst = reverseMatchSrc.clone();
856
857 reverseMatchSrc.setTransportSource(BGP_PORT);
858 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
859 reverseMatchDst.setTransportDestination(BGP_PORT);
860 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
861
862 fm.setMatch(forwardMatchSrc);
863
Jonathan Hart38c84932013-08-10 17:49:27 +1200864 OFMatch forwardIcmpMatch = new OFMatch();
865 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
866 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
867 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
868 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
869
870 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
871 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
872 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
873
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200874 for (FlowEntry flowEntry : path.flowEntries()){
875 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
876 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200877 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200878 try {
879 forwardFlowModSrc = fm.clone();
880 forwardFlowModDst = fm.clone();
881 reverseFlowModSrc = fm.clone();
882 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200883 forwardIcmp = fm.clone();
884 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200885 } catch (CloneNotSupportedException e) {
886 log.warn("Clone failed", e);
887 continue;
888 }
889
890 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
891 forwardFlowModSrc.setMatch(forwardMatchSrc);
892 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
893 .setPort(flowEntry.outPort().value());
894
895 forwardMatchDst.setInputPort(flowEntry.inPort().value());
896 forwardFlowModDst.setMatch(forwardMatchDst);
897 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
898 .setPort(flowEntry.outPort().value());
899
900 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
901 reverseFlowModSrc.setMatch(reverseMatchSrc);
902 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
903 .setPort(flowEntry.inPort().value());
904
905 reverseMatchDst.setInputPort(flowEntry.outPort().value());
906 reverseFlowModDst.setMatch(reverseMatchDst);
907 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
908 .setPort(flowEntry.inPort().value());
909
Jonathan Hart38c84932013-08-10 17:49:27 +1200910 ((OFActionOutput)forwardIcmp.getActions().get(0))
911 .setPort(flowEntry.outPort().value());
912 forwardIcmp.setMatch(forwardIcmpMatch);
913
914 ((OFActionOutput)reverseIcmp.getActions().get(0))
915 .setPort(flowEntry.inPort().value());
916 reverseIcmp.setMatch(reverseIcmpMatch);
917
918
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200919 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
920
Jonathan Hart38c84932013-08-10 17:49:27 +1200921 if (sw == null) {
922 log.warn("Switch not found when pushing BGP paths");
923 return;
924 }
925
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200926 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
927 msgList.add(forwardFlowModSrc);
928 msgList.add(forwardFlowModDst);
929 msgList.add(reverseFlowModSrc);
930 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +1200931 msgList.add(forwardIcmp);
932 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200933
934 try {
935 sw.write(msgList, null);
936 sw.flush();
937 } catch (IOException e) {
938 log.error("Failure writing flow mod", e);
939 }
940 }
941 }
942 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200943
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200944 @Override
945 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
946 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
947 MACAddress.valueOf(macAddress).toString());
948
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200949 /*
950 * We synchronize on this to prevent changes to the ptree while we're pushing
951 * flows to the switches. If the ptree changes, the ptree and switches
952 * could get out of sync.
953 */
954 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200955 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200956
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200957 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200958 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200959 path.getDstIpAddress().getHostAddress(),
Jonathan Hart309889c2013-08-13 23:26:24 +1200960 MACAddress.valueOf(macAddress),
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200961 path.getDstInterface().getSwitchPort()});
962 //These paths should always be to BGP peers. Paths to non-peers are
963 //handled once the first prefix is ready to push
964 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200965 //A path already got pushed to this endpoint while we were waiting
966 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200967 if (path.isPermanent()) {
968 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200969 }
970 }
971 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200972 setUpDataPath(path, MACAddress.valueOf(macAddress));
973 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200974 }
975 }
976
Jonathan Hart309889c2013-08-13 23:26:24 +1200977 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
978
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200979 for (RibUpdate update : prefixesToPush) {
980 //These will always be adds
981
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200982 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200983 if (rib != null && rib.equals(update.getRibEntry())) {
984 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200985 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200986 //We only push prefix flows if the prefix is still in the ptree
987 //and the next hop is the same as our update. The prefix could
988 //have been removed while we were waiting for the ARP, or the
989 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200990 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200991 } else {
992 log.debug("Received ARP response, but {},{} is no longer in ptree",
993 update.getPrefix(), update.getRibEntry());
994 }
995 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200996 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200997 }
998
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200999 private void beginRouting(){
1000 log.debug("Topology is now ready, beginning routing function");
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001001 topoRouteTopology = topoRouteService.prepareShortestPathTopo();
1002
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001003 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001004 setupFullMesh();
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001005
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001006 bgpUpdatesExecutor.execute(new Runnable() {
1007 @Override
1008 public void run() {
1009 doUpdatesThread();
1010 }
1011 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001012 }
1013
1014 private void checkSwitchesConnected(){
1015 for (String dpid : switches){
1016 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1017 log.debug("Not all switches are here yet");
1018 return;
1019 }
1020 }
1021 switchesConnected = true;
1022 }
1023
Jonathan Hartc824ad02013-07-03 15:58:45 +12001024 //Actually we only need to go half way round to verify full mesh connectivity
1025 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001026 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001027 for (Interface dstInterface : interfaces.values()) {
1028 for (Interface srcInterface : interfaces.values()) {
1029 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001030 continue;
1031 }
1032
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001033 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001034 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001035
1036 if (shortestPath == null){
1037 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001038 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001039 return;
1040 }
1041 }
1042 }
1043 topologyReady = true;
1044 }
1045
1046 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001047 if (!switchesConnected){
1048 checkSwitchesConnected();
1049 }
1050 boolean oldTopologyReadyStatus = topologyReady;
1051 if (switchesConnected && !topologyReady){
1052 checkTopologyReady();
1053 }
1054 if (!oldTopologyReadyStatus && topologyReady){
1055 beginRouting();
1056 }
1057 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001058
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001059 private void doUpdatesThread() {
1060 boolean interrupted = false;
1061 try {
1062 while (true) {
1063 try {
1064 RibUpdate update = ribUpdates.take();
1065 switch (update.getOperation()){
1066 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001067 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001068 break;
1069 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001070 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001071 break;
1072 }
1073 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001074 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001075 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001076 } catch (Exception e) {
1077 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001078 }
1079 }
1080 } finally {
1081 if (interrupted) {
1082 Thread.currentThread().interrupt();
1083 }
1084 }
1085 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001086
1087 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001088 public void topologyChanged() {
1089 if (topologyReady) {
1090 return;
1091 }
1092
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001093 boolean refreshNeeded = false;
1094 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1095 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1096 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001097 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001098 refreshNeeded = true;
1099 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001100
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001101 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001102
Jonathan Hart98957bf2013-07-01 14:49:24 +12001103 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1104 synchronized (linkUpdates) {
1105 linkUpdates.add(ldu);
1106 }
1107 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001108 }
1109
Jonathan Hart64c0b202013-08-20 15:45:07 +12001110 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001111 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001112 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001113 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001114
1115 @Override
1116 public void addedSwitch(IOFSwitch sw) {
1117 if (!topologyReady) {
1118 sw.clearAllFlowMods();
1119 }
1120 }
1121
1122 @Override
1123 public void removedSwitch(IOFSwitch sw) {
1124 // TODO Auto-generated method stub
1125
1126 }
1127
1128 @Override
1129 public void switchPortChanged(Long switchId) {
1130 // TODO Auto-generated method stub
1131
1132 }
1133
1134 @Override
1135 public String getName() {
1136 // TODO Auto-generated method stub
1137 return null;
1138 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001139}