blob: 278fb869bba646eb0eab0f5333287f5f9a3cee84 [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;
pingping-lina2cbfad2013-03-07 08:39:21 +080022import net.floodlightcontroller.core.module.FloodlightModuleContext;
23import net.floodlightcontroller.core.module.FloodlightModuleException;
24import net.floodlightcontroller.core.module.IFloodlightModule;
25import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120026import net.floodlightcontroller.core.util.SingletonTask;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070027import net.floodlightcontroller.devicemanager.IDeviceService;
28import 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 Harta23ffdb2013-08-14 14:36:54 +120077 ITopologyListener, IArpRequester {
pingping-lina2cbfad2013-03-07 08:39:21 +080078
79 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
80
81 protected IFloodlightProviderService floodlightProvider;
82 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070083 protected ITopoRouteService topoRouteService;
84 protected IDeviceService devices;
85 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 Hart1236a9b2013-06-18 22:10:05 +1200119
120 //True when all switches have connected
121 protected volatile boolean switchesConnected = false;
122 //True when we have a full mesh of shortest paths between gateways
123 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200124
Jonathan Hart98957bf2013-07-01 14:49:24 +1200125 protected ArrayList<LDUpdate> linkUpdates;
126 protected SingletonTask topologyChangeDetectorTask;
127
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200128 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200129
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200130 protected Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200131
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200132 protected ExecutorService bgpUpdatesExecutor;
133
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200134 protected Map<InetAddress, Path> pushedPaths;
135 protected Map<Prefix, Path> prefixToPath;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200136 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200137
Jonathan Hart98957bf2013-07-01 14:49:24 +1200138 protected class TopologyChangeDetector implements Runnable {
139 @Override
140 public void run() {
141 log.debug("Running topology change detection task");
142 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200143 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200144 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
145
146 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200147
148 Iterator<LDUpdate> it = linkUpdates.iterator();
149 while (it.hasNext()){
150 LDUpdate ldu = it.next();
151 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
152 ldu.getDst(), ldu.getDstPort());
153
154 if (activeLinks.contains(l)){
155 log.debug("Not found: {}", l);
156 it.remove();
157 }
158 }
159 }
160
161 if (linkUpdates.isEmpty()){
162 //All updates have been seen in network map.
163 //We can check if topology is ready
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200164 log.debug("No known changes outstanding. Checking topology now");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200165 checkStatus();
166 }
167 else {
168 //We know of some link updates that haven't propagated to the database yet
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200169 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200170 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
171 }
172 }
173 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700174
Jonathan Hartd1f23252013-06-13 15:17:05 +1200175 private void readGatewaysConfiguration(String gatewaysFilename){
176 File gatewaysFile = new File(gatewaysFilename);
177 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700178
Jonathan Hartd1f23252013-06-13 15:17:05 +1200179 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200180 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
181
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200182 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200183 interfaces = new HashMap<String, Interface>();
184 for (Interface intf : config.getInterfaces()){
185 interfaces.put(intf.getName(), intf);
186 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200187 bgpPeers = new HashMap<InetAddress, BgpPeer>();
188 for (BgpPeer peer : config.getPeers()){
189 bgpPeers.put(peer.getIpAddress(), peer);
190 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200191
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200192 bgpdAttachmentPoint = new SwitchPort(
193 new Dpid(config.getBgpdAttachmentDpid()),
194 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200195
Jonathan Hartd1f23252013-06-13 15:17:05 +1200196 } catch (JsonParseException e) {
197 log.error("Error in JSON file", e);
198 System.exit(1);
199 } catch (JsonMappingException e) {
200 log.error("Error in JSON file", e);
201 System.exit(1);
202 } catch (IOException e) {
203 log.error("Error reading JSON file", e);
204 System.exit(1);
205 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200206
207 //Populate the interface Patricia Trie
208 for (Interface intf : interfaces.values()) {
209 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
210 interfacePtrie.put(prefix, intf);
211 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700212 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800213
214 @Override
215 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700216 Collection<Class<? extends IFloodlightService>> l
217 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800218 l.add(IBgpRouteService.class);
219 return l;
220 }
221
222 @Override
223 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700224 Map<Class<? extends IFloodlightService>, IFloodlightService> m
225 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800226 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800227 return m;
228 }
229
pingping-lina2cbfad2013-03-07 08:39:21 +0800230 @Override
231 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700232 Collection<Class<? extends IFloodlightService>> l
233 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800234 l.add(IFloodlightProviderService.class);
235 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700236 l.add(IDeviceService.class);
237 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800238 return l;
239 }
240
241 @Override
242 public void init(FloodlightModuleContext context)
243 throws FloodlightModuleException {
244
Jonathan Hart29b972d2013-08-12 23:43:51 +1200245 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200246 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200247
248 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200249
pingping-lina2cbfad2013-03-07 08:39:21 +0800250 // Register floodlight provider and REST handler.
251 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800252 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700253 devices = context.getServiceImpl(IDeviceService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200254 restApi = context.getServiceImpl(IRestApiService.class);
255
256 //TODO We'll initialise this here for now, but it should really be done as
257 //part of the controller core
Jonathan Hart6261dcd2013-07-22 17:58:35 +1200258 proxyArp = new ProxyArpManager(floodlightProvider, topology, devices);
pingping-lina2cbfad2013-03-07 08:39:21 +0800259
Jonathan Hart98957bf2013-07-01 14:49:24 +1200260 linkUpdates = new ArrayList<LDUpdate>();
261 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
262 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700263
264 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200265
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200266 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200267 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
268 HashMultimap.<InetAddress, RibUpdate>create());
269
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200270 pushedPaths = new HashMap<InetAddress, Path>();
271 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200272 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
273
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200274 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
275 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
276
Jonathan Hart61ba9372013-05-19 20:10:29 -0700277 //Read in config values
278 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
279 if (bgpdRestIp == null){
280 log.error("BgpdRestIp property not found in config file");
281 System.exit(1);
282 }
283 else {
284 log.info("BgpdRestIp set to {}", bgpdRestIp);
285 }
286
287 routerId = context.getConfigParams(this).get("RouterId");
288 if (routerId == null){
289 log.error("RouterId property not found in config file");
290 System.exit(1);
291 }
292 else {
293 log.info("RouterId set to {}", routerId);
294 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200295
Jonathan Hart9575cb62013-07-05 13:43:49 +1200296 String configFilenameParameter = context.getConfigParams(this).get("configfile");
297 if (configFilenameParameter != null){
298 configFilename = configFilenameParameter;
299 }
300 log.debug("Config file set to {}", configFilename);
301
302 readGatewaysConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200303 }
304
305 @Override
306 public void startUp(FloodlightModuleContext context) {
307 restApi.addRestletRoutable(new BgpRouteWebRoutable());
308 topology.addListener(this);
309
310 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
311
312 //Retrieve the RIB from BGPd during startup
313 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800314 }
315
Jonathan Hart29b972d2013-08-12 23:43:51 +1200316 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800317 return ptree;
318 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700319
320 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200321 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800322 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700323
pingping-line2a09ca2013-03-23 09:33:58 +0800324 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700325 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800326 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700327
pingping-line2a09ca2013-03-23 09:33:58 +0800328 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700329 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800330 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800331
Jonathan Hart61ba9372013-05-19 20:10:29 -0700332 private void retrieveRib(){
333 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
334 String response = RestClient.get(url);
335
336 if (response.equals("")){
337 return;
338 }
339
340 response = response.replaceAll("\"", "'");
341 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
342 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
343 String router_id = jsonObj.getString("router-id");
344
345 int size = rib_json_array.size();
346
347 log.info("Retrived RIB of {} entries from BGPd", size);
348
349 for (int j = 0; j < size; j++) {
350 JSONObject second_json_object = rib_json_array.getJSONObject(j);
351 String prefix = second_json_object.getString("prefix");
352 String nexthop = second_json_object.getString("nexthop");
353
354 //insert each rib entry into the local rib;
355 String[] substring = prefix.split("/");
356 String prefix1 = substring[0];
357 String mask1 = substring[1];
358
359 Prefix p;
360 try {
361 p = new Prefix(prefix1, Integer.valueOf(mask1));
362 } catch (NumberFormatException e) {
363 log.warn("Wrong mask format in RIB JSON: {}", mask1);
364 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200365 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700366 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
367 continue;
368 }
369
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200370 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200371
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200372 try {
373 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
374 } catch (InterruptedException e) {
375 log.debug("Interrupted while pushing onto update queue");
376 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700377 }
378 }
379
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200380 @Override
381 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200382 try {
383 ribUpdates.put(update);
384 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200385 log.debug("Interrupted while putting on ribUpdates queue", e);
386 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200387 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200388 }
389
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200390 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200391 Prefix prefix = update.getPrefix();
392
Jonathan Hart9ea31212013-08-12 21:40:34 +1200393 log.debug("Processing prefix add {}", prefix);
394
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200395 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200396
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200397 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200398 //There was an existing nexthop for this prefix. This update supersedes that,
399 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200400 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200401 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200402
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200403 if (update.getRibEntry().getNextHop().equals(
404 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200405 //Route originated by SDN domain
406 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200407 log.debug("Own route {} to {}", prefix,
408 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200409 return;
410 }
411
412 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200413 }
414
Jonathan Hart309889c2013-08-13 23:26:24 +1200415 private void _processRibAdd(RibUpdate update) {
416 Prefix prefix = update.getPrefix();
417 RibEntry rib = update.getRibEntry();
418
419 InetAddress dstIpAddress = rib.getNextHop();
420
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200421 //See if we know the MAC address of the next hop
Jonathan Hart309889c2013-08-13 23:26:24 +1200422 byte[] nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200423
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200424 //Find the attachment point (egress interface) of the next hop
425 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200426 if (bgpPeers.containsKey(dstIpAddress)) {
427 //Route to a peer
428 log.debug("Route to peer {}", dstIpAddress);
429 BgpPeer peer = bgpPeers.get(dstIpAddress);
430 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200431 }
432 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200433 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200434 log.debug("Route to non-peer {}", dstIpAddress);
435 egressInterface = interfacePtrie.match(
436 new Prefix(dstIpAddress.getAddress(), 32));
437 if (egressInterface == null) {
438 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
439 return;
440 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200441 }
442
443 if (nextHopMacAddress == null) {
444 prefixesWaitingOnArp.put(dstIpAddress,
445 new RibUpdate(Operation.UPDATE, prefix, rib));
446 proxyArp.sendArpRequest(dstIpAddress, this, true);
447 return;
448 }
449 else {
450 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200451 //If the prefix is for a non-peer we need to ensure there's a path,
452 //and push one if there isn't.
453 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200454 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200455 path = new Path(egressInterface, dstIpAddress);
456 setUpDataPath(path, MACAddress.valueOf(nextHopMacAddress));
Jonathan Hart309889c2013-08-13 23:26:24 +1200457 pushedPaths.put(dstIpAddress, path);
458 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200459
460 path.incrementUsers();
461 prefixToPath.put(prefix, path);
462 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200463
464 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200465 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
466 }
467 }
468
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200469 private void addPrefixFlows(Prefix prefix, Interface egressInterface, byte[] nextHopMacAddress) {
470 log.debug("Adding flows for prefix {} added, next hop mac {}",
471 prefix, HexString.toHexString(nextHopMacAddress));
472
473 //Add a flow to rewrite mac for this prefix to all other border switches
474 for (Interface srcInterface : interfaces.values()) {
475 if (srcInterface == egressInterface) {
476 //Don't push a flow for the switch where this peer is attached
477 continue;
478 }
479
480 DataPath shortestPath = topoRouteService.getShortestPath(
481 srcInterface.getSwitchPort(),
482 egressInterface.getSwitchPort());
483
484 if (shortestPath == null){
485 log.debug("Shortest path between {} and {} not found",
486 srcInterface.getSwitchPort(),
487 egressInterface.getSwitchPort());
488 return; // just quit here?
489 }
490
491 //Set up the flow mod
492 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
493 .getMessage(OFType.FLOW_MOD);
494
495 fm.setIdleTimeout((short)0)
496 .setHardTimeout((short)0)
497 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
498 .setCookie(MAC_RW_COOKIE)
499 .setCommand(OFFlowMod.OFPFC_ADD)
500 .setPriority(SDNIP_PRIORITY)
501 .setLengthU(OFFlowMod.MINIMUM_LENGTH
502 + OFActionDataLayerDestination.MINIMUM_LENGTH
503 + OFActionOutput.MINIMUM_LENGTH);
504
505 OFMatch match = new OFMatch();
506 match.setDataLayerType(Ethernet.TYPE_IPv4);
507 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
508
509 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
510 fm.setMatch(match);
511
512 //Set up MAC rewrite action
513 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
514 macRewriteAction.setDataLayerAddress(nextHopMacAddress);
515
516 //Set up output action
517 OFActionOutput outputAction = new OFActionOutput();
518 outputAction.setMaxLength((short)0xffff);
519 Port outputPort = shortestPath.flowEntries().get(0).outPort();
520 outputAction.setPort(outputPort.value());
521
522 List<OFAction> actions = new ArrayList<OFAction>();
523 actions.add(macRewriteAction);
524 actions.add(outputAction);
525 fm.setActions(actions);
526
527 //Write to switch
528 IOFSwitch sw = floodlightProvider.getSwitches()
529 .get(srcInterface.getDpid());
530
531 if (sw == null){
532 log.warn("Switch not found when pushing flow mod");
533 continue;
534 }
535
536 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
537
538 List<OFMessage> msglist = new ArrayList<OFMessage>();
539 msglist.add(fm);
540 try {
541 sw.write(msglist, null);
542 sw.flush();
543 } catch (IOException e) {
544 log.error("Failure writing flow mod", e);
545 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200546 }
547 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200548
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200549 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200550 Prefix prefix = update.getPrefix();
551
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200552 if (ptree.remove(prefix, update.getRibEntry())) {
553 /*
554 * Only delete flows if an entry was actually removed from the trie.
555 * If no entry was removed, the <prefix, nexthop> wasn't there so
556 * it's probably already been removed and we don't need to do anything
557 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200558 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200559 }
560 }
561
562 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
563 deletePrefixFlows(prefix);
564
565 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
566 log.debug("is peer {}", bgpPeers.containsKey(ribEntry.getNextHop()));
567 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
568 log.debug("Getting path for route with non-peer nexthop");
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200569 Path path = prefixToPath.get(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200570
571 if (path == null) {
572 log.error("No path found for non-peer path");
573 }
574
575 path.decrementUsers();
576 log.debug("users {}, permanent {}", path.getUsers(), path.isPermanent());
577 if (path.getUsers() <= 0 && !path.isPermanent()) {
578 deletePath(path);
579 }
580 }
581 }
582
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200583 private void deletePrefixFlows(Prefix prefix) {
584 Collection<PushedFlowMod> pushedFlowMods
585 = pushedFlows.removeAll(prefix);
586
587 for (PushedFlowMod pfm : pushedFlowMods) {
588 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
589 new Object[] {HexString.toHexString(pfm.getDpid()),
590 pfm.getFlowMod().getMatch().getNetworkDestination() +
591 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
592 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
593 .getDataLayerAddress())});
594
595 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
596 }
597 }
598
599 private void deletePath(Path path) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200600 for (PushedFlowMod pfm : path.getFlowMods()) {
601 log.debug("Pushing a DELETE flow mod to {}, dst MAC {}",
602 new Object[] {HexString.toHexString(pfm.getDpid()),
603 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
604 });
605
606 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
607 }
608 }
609
610 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
611 addFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
612 .setOutPort(OFPort.OFPP_NONE)
613 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
614
615 addFlowMod.getActions().clear();
616
617 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
618 if (sw == null) {
619 log.warn("Switch not found when pushing delete flow mod");
620 return;
621 }
622
623 try {
624 sw.write(addFlowMod, null);
625 sw.flush();
626 } catch (IOException e) {
627 log.error("Failure writing flow mod", e);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200628 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200629 }
630
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200631 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200632 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200633
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700634 /*
635 * On startup we need to calculate a full mesh of paths between all gateway
636 * switches
637 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200638 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700639 //For each border router, calculate and install a path from every other
640 //border switch to said border router. However, don't install the entry
641 //in to the first hop switch, as we need to install an entry to rewrite
642 //for each prefix received. This will be done later when prefixes have
643 //actually been received.
644
Jonathan Hartc824ad02013-07-03 15:58:45 +1200645 for (BgpPeer peer : bgpPeers.values()) {
646 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200647
Jonathan Hart309889c2013-08-13 23:26:24 +1200648 //We know there's not already a Path here pushed, because this is
649 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200650 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200651 path.setPermanent();
652
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200653 //See if we know the MAC address of the peer. If not we can't
654 //do anything until we learn it
655 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
656 if (mac == null) {
657 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
658 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200659 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700660
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200661 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
662 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700663 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200664
665 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200666 setUpDataPath(path, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700667 }
668 }
669
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200670 private void setUpDataPath(Path path, MACAddress dstMacAddress) {
671 calculateAndPushPath(path, dstMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200672 }
673
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200674 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200675 Interface dstInterface = path.getDstInterface();
676
677 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
678
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200679 for (Interface srcInterface : interfaces.values()) {
680 if (dstInterface.equals(srcInterface.getName())){
681 continue;
682 }
683
684 DataPath shortestPath = topoRouteService.getShortestPath(
685 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
686
687 if (shortestPath == null){
688 log.debug("Shortest path between {} and {} not found",
689 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
690 return; // just quit here?
691 }
692
Jonathan Hart309889c2013-08-13 23:26:24 +1200693 pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200694 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200695
696 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200697 }
698
Jonathan Hart309889c2013-08-13 23:26:24 +1200699 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
700 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
701
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700702 //Set up the flow mod
703 OFFlowMod fm =
704 (OFFlowMod) floodlightProvider.getOFMessageFactory()
705 .getMessage(OFType.FLOW_MOD);
706
707 OFActionOutput action = new OFActionOutput();
708 action.setMaxLength((short)0xffff);
709 List<OFAction> actions = new ArrayList<OFAction>();
710 actions.add(action);
711
712 fm.setIdleTimeout((short)0)
713 .setHardTimeout((short)0)
714 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
715 .setCookie(L2_FWD_COOKIE)
716 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700717 .setActions(actions)
718 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
719
720 //Don't push the first flow entry. We need to push entries in the
721 //first switch based on IP prefix which we don't know yet.
722 for (int i = 1; i < flowEntries.size(); i++){
723 FlowEntry flowEntry = flowEntries.get(i);
724
725 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200726 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700727 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
728 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
729
730 fm.setMatch(match);
731
732 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
733
734 if (sw == null){
735 log.warn("Switch not found when pushing flow mod");
736 continue;
737 }
738
Jonathan Hart309889c2013-08-13 23:26:24 +1200739 flowMods.add(new PushedFlowMod(sw.getId(), fm));
740
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700741 List<OFMessage> msglist = new ArrayList<OFMessage>();
742 msglist.add(fm);
743 try {
744 sw.write(msglist, null);
745 sw.flush();
746 } catch (IOException e) {
747 log.error("Failure writing flow mod", e);
748 }
749
750 try {
751 fm = fm.clone();
752 } catch (CloneNotSupportedException e1) {
753 log.error("Failure cloning flow mod", e1);
754 }
755 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200756
757 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700758 }
759
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200760 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200761 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200762 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
763
764 DataPath path = topoRouteService.getShortestPath(
765 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
766
767 if (path == null){
768 log.debug("Unable to compute path for BGP traffic for {}",
769 bgpPeer.getIpAddress());
770 continue;
771 }
772
773 //Set up the flow mod
774 OFFlowMod fm =
775 (OFFlowMod) floodlightProvider.getOFMessageFactory()
776 .getMessage(OFType.FLOW_MOD);
777
778 OFActionOutput action = new OFActionOutput();
779 action.setMaxLength((short)0xffff);
780 List<OFAction> actions = new ArrayList<OFAction>();
781 actions.add(action);
782
783 fm.setIdleTimeout((short)0)
784 .setHardTimeout((short)0)
785 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
786 .setCookie(BGP_COOKIE)
787 .setCommand(OFFlowMod.OFPFC_ADD)
788 .setPriority(SDNIP_PRIORITY)
789 .setActions(actions)
790 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
791
792 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
793 OFMatch forwardMatchSrc = new OFMatch();
794
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200795 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
796 + "/32";
797 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
798 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200799
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200800 //Common match fields
801 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200802 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
803 forwardMatchSrc.setTransportDestination(BGP_PORT);
804 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
805 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
806
807
808 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
809
810 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
811 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
812
813 OFMatch forwardMatchDst = forwardMatchSrc.clone();
814
815 forwardMatchSrc.setTransportSource(BGP_PORT);
816 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
817 forwardMatchDst.setTransportDestination(BGP_PORT);
818 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
819
820 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
821 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
822
823 OFMatch reverseMatchDst = reverseMatchSrc.clone();
824
825 reverseMatchSrc.setTransportSource(BGP_PORT);
826 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
827 reverseMatchDst.setTransportDestination(BGP_PORT);
828 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
829
830 fm.setMatch(forwardMatchSrc);
831
Jonathan Hart38c84932013-08-10 17:49:27 +1200832 OFMatch forwardIcmpMatch = new OFMatch();
833 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
834 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
835 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
836 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
837
838 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
839 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
840 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
841
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200842 for (FlowEntry flowEntry : path.flowEntries()){
843 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
844 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200845 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200846 try {
847 forwardFlowModSrc = fm.clone();
848 forwardFlowModDst = fm.clone();
849 reverseFlowModSrc = fm.clone();
850 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200851 forwardIcmp = fm.clone();
852 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200853 } catch (CloneNotSupportedException e) {
854 log.warn("Clone failed", e);
855 continue;
856 }
857
858 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
859 forwardFlowModSrc.setMatch(forwardMatchSrc);
860 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
861 .setPort(flowEntry.outPort().value());
862
863 forwardMatchDst.setInputPort(flowEntry.inPort().value());
864 forwardFlowModDst.setMatch(forwardMatchDst);
865 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
866 .setPort(flowEntry.outPort().value());
867
868 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
869 reverseFlowModSrc.setMatch(reverseMatchSrc);
870 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
871 .setPort(flowEntry.inPort().value());
872
873 reverseMatchDst.setInputPort(flowEntry.outPort().value());
874 reverseFlowModDst.setMatch(reverseMatchDst);
875 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
876 .setPort(flowEntry.inPort().value());
877
Jonathan Hart38c84932013-08-10 17:49:27 +1200878 ((OFActionOutput)forwardIcmp.getActions().get(0))
879 .setPort(flowEntry.outPort().value());
880 forwardIcmp.setMatch(forwardIcmpMatch);
881
882 ((OFActionOutput)reverseIcmp.getActions().get(0))
883 .setPort(flowEntry.inPort().value());
884 reverseIcmp.setMatch(reverseIcmpMatch);
885
886
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200887 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
888
Jonathan Hart38c84932013-08-10 17:49:27 +1200889 if (sw == null) {
890 log.warn("Switch not found when pushing BGP paths");
891 return;
892 }
893
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200894 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
895 msgList.add(forwardFlowModSrc);
896 msgList.add(forwardFlowModDst);
897 msgList.add(reverseFlowModSrc);
898 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +1200899 msgList.add(forwardIcmp);
900 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200901
902 try {
903 sw.write(msgList, null);
904 sw.flush();
905 } catch (IOException e) {
906 log.error("Failure writing flow mod", e);
907 }
908 }
909 }
910 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200911
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200912 @Override
913 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
914 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
915 MACAddress.valueOf(macAddress).toString());
916
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200917 /*
918 * We synchronize on this to prevent changes to the ptree while we're pushing
919 * flows to the switches. If the ptree changes, the ptree and switches
920 * could get out of sync.
921 */
922 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200923 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200924
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200925 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200926 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200927 path.getDstIpAddress().getHostAddress(),
Jonathan Hart309889c2013-08-13 23:26:24 +1200928 MACAddress.valueOf(macAddress),
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200929 path.getDstInterface().getSwitchPort()});
930 //These paths should always be to BGP peers. Paths to non-peers are
931 //handled once the first prefix is ready to push
932 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200933 //A path already got pushed to this endpoint while we were waiting
934 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200935 if (path.isPermanent()) {
936 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200937 }
938 }
939 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200940 setUpDataPath(path, MACAddress.valueOf(macAddress));
941 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200942 }
943 }
944
Jonathan Hart309889c2013-08-13 23:26:24 +1200945 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
946
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200947 for (RibUpdate update : prefixesToPush) {
948 //These will always be adds
949
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200950 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200951 if (rib != null && rib.equals(update.getRibEntry())) {
952 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200953 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200954 //We only push prefix flows if the prefix is still in the ptree
955 //and the next hop is the same as our update. The prefix could
956 //have been removed while we were waiting for the ARP, or the
957 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200958 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200959 } else {
960 log.debug("Received ARP response, but {},{} is no longer in ptree",
961 update.getPrefix(), update.getRibEntry());
962 }
963 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200964 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200965 }
966
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200967 private void beginRouting(){
968 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200969 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200970 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200971
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200972 bgpUpdatesExecutor.execute(new Runnable() {
973 @Override
974 public void run() {
975 doUpdatesThread();
976 }
977 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200978 }
979
980 private void checkSwitchesConnected(){
981 for (String dpid : switches){
982 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
983 log.debug("Not all switches are here yet");
984 return;
985 }
986 }
987 switchesConnected = true;
988 }
989
Jonathan Hartc824ad02013-07-03 15:58:45 +1200990 //Actually we only need to go half way round to verify full mesh connectivity
991 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200992 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200993 for (Interface dstInterface : interfaces.values()) {
994 for (Interface srcInterface : interfaces.values()) {
995 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200996 continue;
997 }
998
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200999 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001000 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001001
1002 if (shortestPath == null){
1003 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001004 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001005 return;
1006 }
1007 }
1008 }
1009 topologyReady = true;
1010 }
1011
1012 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001013 if (!switchesConnected){
1014 checkSwitchesConnected();
1015 }
1016 boolean oldTopologyReadyStatus = topologyReady;
1017 if (switchesConnected && !topologyReady){
1018 checkTopologyReady();
1019 }
1020 if (!oldTopologyReadyStatus && topologyReady){
1021 beginRouting();
1022 }
1023 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001024
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001025 private void doUpdatesThread() {
1026 boolean interrupted = false;
1027 try {
1028 while (true) {
1029 try {
1030 RibUpdate update = ribUpdates.take();
1031 switch (update.getOperation()){
1032 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001033 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001034 break;
1035 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001036 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001037 break;
1038 }
1039 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001040 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001041 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001042 } catch (Exception e) {
1043 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001044 }
1045 }
1046 } finally {
1047 if (interrupted) {
1048 Thread.currentThread().interrupt();
1049 }
1050 }
1051 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001052
1053 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001054 public void topologyChanged() {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001055 boolean refreshNeeded = false;
1056 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1057 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1058 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001059 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001060 refreshNeeded = true;
1061 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001062
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001063 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001064
Jonathan Hart98957bf2013-07-01 14:49:24 +12001065 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1066 synchronized (linkUpdates) {
1067 linkUpdates.add(ldu);
1068 }
1069 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001070 }
1071
1072 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001073 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001074 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001075 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001076}