blob: d72c52c029c70e86a7d4342e066b8f4911c0d2ec [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.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120028import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080029import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120030import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080031import net.floodlightcontroller.topology.ITopologyListener;
32import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120033import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120034import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
Jonathan Hart98957bf2013-07-01 14:49:24 +120035import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070036import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120037import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070038import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
39import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120040import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120041import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070042import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070043import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120044import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070045import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070046import net.onrc.onos.ofcontroller.util.Port;
47import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080048import net.sf.json.JSONArray;
49import net.sf.json.JSONObject;
50import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080051
Jonathan Hartd1f23252013-06-13 15:17:05 +120052import org.codehaus.jackson.JsonParseException;
53import org.codehaus.jackson.map.JsonMappingException;
54import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070055import org.openflow.protocol.OFFlowMod;
56import org.openflow.protocol.OFMatch;
57import org.openflow.protocol.OFMessage;
58import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120059import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070060import org.openflow.protocol.OFType;
61import org.openflow.protocol.action.OFAction;
62import org.openflow.protocol.action.OFActionDataLayerDestination;
63import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120064import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080065import org.slf4j.Logger;
66import org.slf4j.LoggerFactory;
67
Jonathan Hart4dfc3652013-08-02 20:22:36 +120068import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120069import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120070import com.google.common.collect.Multimaps;
71import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120072import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120073import com.google.common.util.concurrent.ThreadFactoryBuilder;
74
Jonathan Hart1236a9b2013-06-18 22:10:05 +120075public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Harta23ffdb2013-08-14 14:36:54 +120076 ITopologyListener, IArpRequester {
pingping-lina2cbfad2013-03-07 08:39:21 +080077
78 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
79
80 protected IFloodlightProviderService floodlightProvider;
81 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070082 protected ITopoRouteService topoRouteService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070083 protected IRestApiService restApi;
84
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120085 protected ProxyArpManager proxyArp;
86
Jonathan Hart29b972d2013-08-12 23:43:51 +120087 protected IPatriciaTrie<RibEntry> ptree;
Jonathan Hartabf10222013-08-13 10:19:34 +120088 protected IPatriciaTrie<Interface> interfacePtrie;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120089 protected BlockingQueue<RibUpdate> ribUpdates;
90
Jonathan Hart61ba9372013-05-19 20:10:29 -070091 protected String bgpdRestIp;
92 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120093 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070094
95 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
96 //the controller/OS should hand out cookie IDs to prevent conflicts.
97 protected final long APP_COOKIE = 0xa0000000000000L;
98 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
99 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
100 //Cookie for flows in ingress switches that rewrite the MAC address
101 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200102 //Cookie for flows that setup BGP paths
103 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200104 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
105 //need to be higher priority than this otherwise the rewrite may not get done
106 protected final short SDNIP_PRIORITY = 10;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700107
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200108 protected final short BGP_PORT = 179;
109
Jonathan Hart98957bf2013-07-01 14:49:24 +1200110 protected final int TOPO_DETECTION_WAIT = 2; //seconds
111
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200112 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200113 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200114 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200115 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200116 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart2f790d22013-08-15 14:01:24 +1200117 protected MACAddress bgpdMacAddress;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200118
119 //True when all switches have connected
120 protected volatile boolean switchesConnected = false;
121 //True when we have a full mesh of shortest paths between gateways
122 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200123
Jonathan Hart98957bf2013-07-01 14:49:24 +1200124 protected ArrayList<LDUpdate> linkUpdates;
125 protected SingletonTask topologyChangeDetectorTask;
126
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200127 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200128
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200129 protected Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200130
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200131 protected ExecutorService bgpUpdatesExecutor;
132
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200133 protected Map<InetAddress, Path> pushedPaths;
134 protected Map<Prefix, Path> prefixToPath;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200135 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200136
Jonathan Hart98957bf2013-07-01 14:49:24 +1200137 protected class TopologyChangeDetector implements Runnable {
138 @Override
139 public void run() {
140 log.debug("Running topology change detection task");
141 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200142 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200143 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
144
145 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200146
147 Iterator<LDUpdate> it = linkUpdates.iterator();
148 while (it.hasNext()){
149 LDUpdate ldu = it.next();
150 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
151 ldu.getDst(), ldu.getDstPort());
152
153 if (activeLinks.contains(l)){
154 log.debug("Not found: {}", l);
155 it.remove();
156 }
157 }
158 }
159
160 if (linkUpdates.isEmpty()){
161 //All updates have been seen in network map.
162 //We can check if topology is ready
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200163 log.debug("No known changes outstanding. Checking topology now");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200164 checkStatus();
165 }
166 else {
167 //We know of some link updates that haven't propagated to the database yet
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200168 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200169 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
170 }
171 }
172 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700173
Jonathan Hartd1f23252013-06-13 15:17:05 +1200174 private void readGatewaysConfiguration(String gatewaysFilename){
175 File gatewaysFile = new File(gatewaysFilename);
176 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700177
Jonathan Hartd1f23252013-06-13 15:17:05 +1200178 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200179 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
180
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200181 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200182 interfaces = new HashMap<String, Interface>();
183 for (Interface intf : config.getInterfaces()){
184 interfaces.put(intf.getName(), intf);
185 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200186 bgpPeers = new HashMap<InetAddress, BgpPeer>();
187 for (BgpPeer peer : config.getPeers()){
188 bgpPeers.put(peer.getIpAddress(), peer);
189 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200190
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200191 bgpdAttachmentPoint = new SwitchPort(
192 new Dpid(config.getBgpdAttachmentDpid()),
193 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200194
Jonathan Hart2f790d22013-08-15 14:01:24 +1200195 bgpdMacAddress = config.getBgpdMacAddress();
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(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800237 return l;
238 }
239
240 @Override
241 public void init(FloodlightModuleContext context)
242 throws FloodlightModuleException {
243
Jonathan Hart29b972d2013-08-12 23:43:51 +1200244 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200245 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200246
247 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200248
pingping-lina2cbfad2013-03-07 08:39:21 +0800249 // Register floodlight provider and REST handler.
250 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800251 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200252 restApi = context.getServiceImpl(IRestApiService.class);
253
254 //TODO We'll initialise this here for now, but it should really be done as
255 //part of the controller core
Jonathan Hart2f790d22013-08-15 14:01:24 +1200256 proxyArp = new ProxyArpManager(floodlightProvider, topology);
pingping-lina2cbfad2013-03-07 08:39:21 +0800257
Jonathan Hart98957bf2013-07-01 14:49:24 +1200258 linkUpdates = new ArrayList<LDUpdate>();
259 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
260 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700261
262 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200263
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200264 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200265 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
266 HashMultimap.<InetAddress, RibUpdate>create());
267
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200268 pushedPaths = new HashMap<InetAddress, Path>();
269 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200270 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
271
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200272 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
273 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
274
Jonathan Hart61ba9372013-05-19 20:10:29 -0700275 //Read in config values
276 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
277 if (bgpdRestIp == null){
278 log.error("BgpdRestIp property not found in config file");
279 System.exit(1);
280 }
281 else {
282 log.info("BgpdRestIp set to {}", bgpdRestIp);
283 }
284
285 routerId = context.getConfigParams(this).get("RouterId");
286 if (routerId == null){
287 log.error("RouterId property not found in config file");
288 System.exit(1);
289 }
290 else {
291 log.info("RouterId set to {}", routerId);
292 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200293
Jonathan Hart9575cb62013-07-05 13:43:49 +1200294 String configFilenameParameter = context.getConfigParams(this).get("configfile");
295 if (configFilenameParameter != null){
296 configFilename = configFilenameParameter;
297 }
298 log.debug("Config file set to {}", configFilename);
299
300 readGatewaysConfiguration(configFilename);
Jonathan Hart2f790d22013-08-15 14:01:24 +1200301
302 proxyArp.setL3Mode(interfacePtrie, bgpdMacAddress);
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
Jonathan Hart2f790d22013-08-15 14:01:24 +1200310 proxyArp.startUp();
311
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200312 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
313
314 //Retrieve the RIB from BGPd during startup
315 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800316 }
317
Jonathan Hart29b972d2013-08-12 23:43:51 +1200318 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800319 return ptree;
320 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700321
322 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200323 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800324 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700325
pingping-line2a09ca2013-03-23 09:33:58 +0800326 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700327 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800328 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700329
pingping-line2a09ca2013-03-23 09:33:58 +0800330 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700331 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800332 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800333
Jonathan Hart61ba9372013-05-19 20:10:29 -0700334 private void retrieveRib(){
335 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
336 String response = RestClient.get(url);
337
338 if (response.equals("")){
339 return;
340 }
341
342 response = response.replaceAll("\"", "'");
343 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
344 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
345 String router_id = jsonObj.getString("router-id");
346
347 int size = rib_json_array.size();
348
349 log.info("Retrived RIB of {} entries from BGPd", size);
350
351 for (int j = 0; j < size; j++) {
352 JSONObject second_json_object = rib_json_array.getJSONObject(j);
353 String prefix = second_json_object.getString("prefix");
354 String nexthop = second_json_object.getString("nexthop");
355
356 //insert each rib entry into the local rib;
357 String[] substring = prefix.split("/");
358 String prefix1 = substring[0];
359 String mask1 = substring[1];
360
361 Prefix p;
362 try {
363 p = new Prefix(prefix1, Integer.valueOf(mask1));
364 } catch (NumberFormatException e) {
365 log.warn("Wrong mask format in RIB JSON: {}", mask1);
366 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200367 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700368 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
369 continue;
370 }
371
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200372 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200373
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200374 try {
375 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
376 } catch (InterruptedException e) {
377 log.debug("Interrupted while pushing onto update queue");
378 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700379 }
380 }
381
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200382 @Override
383 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200384 try {
385 ribUpdates.put(update);
386 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200387 log.debug("Interrupted while putting on ribUpdates queue", e);
388 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200389 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200390 }
391
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200392 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200393 Prefix prefix = update.getPrefix();
394
Jonathan Hart9ea31212013-08-12 21:40:34 +1200395 log.debug("Processing prefix add {}", prefix);
396
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200397 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200398
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200399 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200400 //There was an existing nexthop for this prefix. This update supersedes that,
401 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200402 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200403 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200404
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200405 if (update.getRibEntry().getNextHop().equals(
406 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200407 //Route originated by SDN domain
408 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200409 log.debug("Own route {} to {}", prefix,
410 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200411 return;
412 }
413
414 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200415 }
416
Jonathan Hart309889c2013-08-13 23:26:24 +1200417 private void _processRibAdd(RibUpdate update) {
418 Prefix prefix = update.getPrefix();
419 RibEntry rib = update.getRibEntry();
420
421 InetAddress dstIpAddress = rib.getNextHop();
422
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200423 //See if we know the MAC address of the next hop
Jonathan Hart309889c2013-08-13 23:26:24 +1200424 byte[] nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200425
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200426 //Find the attachment point (egress interface) of the next hop
427 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200428 if (bgpPeers.containsKey(dstIpAddress)) {
429 //Route to a peer
430 log.debug("Route to peer {}", dstIpAddress);
431 BgpPeer peer = bgpPeers.get(dstIpAddress);
432 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200433 }
434 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200435 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200436 log.debug("Route to non-peer {}", dstIpAddress);
437 egressInterface = interfacePtrie.match(
438 new Prefix(dstIpAddress.getAddress(), 32));
439 if (egressInterface == null) {
440 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
441 return;
442 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200443 }
444
445 if (nextHopMacAddress == null) {
446 prefixesWaitingOnArp.put(dstIpAddress,
447 new RibUpdate(Operation.UPDATE, prefix, rib));
448 proxyArp.sendArpRequest(dstIpAddress, this, true);
449 return;
450 }
451 else {
452 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200453 //If the prefix is for a non-peer we need to ensure there's a path,
454 //and push one if there isn't.
455 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200456 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200457 path = new Path(egressInterface, dstIpAddress);
458 setUpDataPath(path, MACAddress.valueOf(nextHopMacAddress));
Jonathan Hart309889c2013-08-13 23:26:24 +1200459 pushedPaths.put(dstIpAddress, path);
460 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200461
462 path.incrementUsers();
463 prefixToPath.put(prefix, path);
464 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200465
466 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200467 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
468 }
469 }
470
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200471 private void addPrefixFlows(Prefix prefix, Interface egressInterface, byte[] nextHopMacAddress) {
472 log.debug("Adding flows for prefix {} added, next hop mac {}",
473 prefix, HexString.toHexString(nextHopMacAddress));
474
475 //Add a flow to rewrite mac for this prefix to all other border switches
476 for (Interface srcInterface : interfaces.values()) {
477 if (srcInterface == egressInterface) {
478 //Don't push a flow for the switch where this peer is attached
479 continue;
480 }
481
482 DataPath shortestPath = topoRouteService.getShortestPath(
483 srcInterface.getSwitchPort(),
484 egressInterface.getSwitchPort());
485
486 if (shortestPath == null){
487 log.debug("Shortest path between {} and {} not found",
488 srcInterface.getSwitchPort(),
489 egressInterface.getSwitchPort());
490 return; // just quit here?
491 }
492
493 //Set up the flow mod
494 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
495 .getMessage(OFType.FLOW_MOD);
496
497 fm.setIdleTimeout((short)0)
498 .setHardTimeout((short)0)
499 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
500 .setCookie(MAC_RW_COOKIE)
501 .setCommand(OFFlowMod.OFPFC_ADD)
502 .setPriority(SDNIP_PRIORITY)
503 .setLengthU(OFFlowMod.MINIMUM_LENGTH
504 + OFActionDataLayerDestination.MINIMUM_LENGTH
505 + OFActionOutput.MINIMUM_LENGTH);
506
507 OFMatch match = new OFMatch();
508 match.setDataLayerType(Ethernet.TYPE_IPv4);
509 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
510
511 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
512 fm.setMatch(match);
513
514 //Set up MAC rewrite action
515 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
516 macRewriteAction.setDataLayerAddress(nextHopMacAddress);
517
518 //Set up output action
519 OFActionOutput outputAction = new OFActionOutput();
520 outputAction.setMaxLength((short)0xffff);
521 Port outputPort = shortestPath.flowEntries().get(0).outPort();
522 outputAction.setPort(outputPort.value());
523
524 List<OFAction> actions = new ArrayList<OFAction>();
525 actions.add(macRewriteAction);
526 actions.add(outputAction);
527 fm.setActions(actions);
528
529 //Write to switch
530 IOFSwitch sw = floodlightProvider.getSwitches()
531 .get(srcInterface.getDpid());
532
533 if (sw == null){
534 log.warn("Switch not found when pushing flow mod");
535 continue;
536 }
537
538 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
539
540 List<OFMessage> msglist = new ArrayList<OFMessage>();
541 msglist.add(fm);
542 try {
543 sw.write(msglist, null);
544 sw.flush();
545 } catch (IOException e) {
546 log.error("Failure writing flow mod", e);
547 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200548 }
549 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200550
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200551 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200552 Prefix prefix = update.getPrefix();
553
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200554 if (ptree.remove(prefix, update.getRibEntry())) {
555 /*
556 * Only delete flows if an entry was actually removed from the trie.
557 * If no entry was removed, the <prefix, nexthop> wasn't there so
558 * it's probably already been removed and we don't need to do anything
559 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200560 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200561 }
562 }
563
564 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
565 deletePrefixFlows(prefix);
566
567 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
568 log.debug("is peer {}", bgpPeers.containsKey(ribEntry.getNextHop()));
569 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
570 log.debug("Getting path for route with non-peer nexthop");
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200571 Path path = prefixToPath.get(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200572
573 if (path == null) {
574 log.error("No path found for non-peer path");
575 }
576
577 path.decrementUsers();
578 log.debug("users {}, permanent {}", path.getUsers(), path.isPermanent());
579 if (path.getUsers() <= 0 && !path.isPermanent()) {
580 deletePath(path);
581 }
582 }
583 }
584
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200585 private void deletePrefixFlows(Prefix prefix) {
586 Collection<PushedFlowMod> pushedFlowMods
587 = pushedFlows.removeAll(prefix);
588
589 for (PushedFlowMod pfm : pushedFlowMods) {
590 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
591 new Object[] {HexString.toHexString(pfm.getDpid()),
592 pfm.getFlowMod().getMatch().getNetworkDestination() +
593 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
594 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
595 .getDataLayerAddress())});
596
597 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
598 }
599 }
600
601 private void deletePath(Path path) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200602 for (PushedFlowMod pfm : path.getFlowMods()) {
603 log.debug("Pushing a DELETE flow mod to {}, dst MAC {}",
604 new Object[] {HexString.toHexString(pfm.getDpid()),
605 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
606 });
607
608 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
609 }
610 }
611
612 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
613 addFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
614 .setOutPort(OFPort.OFPP_NONE)
615 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
616
617 addFlowMod.getActions().clear();
618
619 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
620 if (sw == null) {
621 log.warn("Switch not found when pushing delete flow mod");
622 return;
623 }
624
625 try {
626 sw.write(addFlowMod, null);
627 sw.flush();
628 } catch (IOException e) {
629 log.error("Failure writing flow mod", e);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200630 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200631 }
632
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200633 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200634 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200635
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700636 /*
637 * On startup we need to calculate a full mesh of paths between all gateway
638 * switches
639 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200640 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700641 //For each border router, calculate and install a path from every other
642 //border switch to said border router. However, don't install the entry
643 //in to the first hop switch, as we need to install an entry to rewrite
644 //for each prefix received. This will be done later when prefixes have
645 //actually been received.
646
Jonathan Hartc824ad02013-07-03 15:58:45 +1200647 for (BgpPeer peer : bgpPeers.values()) {
648 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200649
Jonathan Hart309889c2013-08-13 23:26:24 +1200650 //We know there's not already a Path here pushed, because this is
651 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200652 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200653 path.setPermanent();
654
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200655 //See if we know the MAC address of the peer. If not we can't
656 //do anything until we learn it
657 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
658 if (mac == null) {
659 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
660 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200661 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700662
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200663 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
664 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700665 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200666
667 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200668 setUpDataPath(path, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700669 }
670 }
671
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200672 private void setUpDataPath(Path path, MACAddress dstMacAddress) {
673 calculateAndPushPath(path, dstMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200674 }
675
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200676 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200677 Interface dstInterface = path.getDstInterface();
678
679 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
680
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200681 for (Interface srcInterface : interfaces.values()) {
682 if (dstInterface.equals(srcInterface.getName())){
683 continue;
684 }
685
686 DataPath shortestPath = topoRouteService.getShortestPath(
687 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
688
689 if (shortestPath == null){
690 log.debug("Shortest path between {} and {} not found",
691 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
692 return; // just quit here?
693 }
694
Jonathan Hart309889c2013-08-13 23:26:24 +1200695 pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200696 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200697
698 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200699 }
700
Jonathan Hart309889c2013-08-13 23:26:24 +1200701 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
702 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
703
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700704 //Set up the flow mod
705 OFFlowMod fm =
706 (OFFlowMod) floodlightProvider.getOFMessageFactory()
707 .getMessage(OFType.FLOW_MOD);
708
709 OFActionOutput action = new OFActionOutput();
710 action.setMaxLength((short)0xffff);
711 List<OFAction> actions = new ArrayList<OFAction>();
712 actions.add(action);
713
714 fm.setIdleTimeout((short)0)
715 .setHardTimeout((short)0)
716 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
717 .setCookie(L2_FWD_COOKIE)
718 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700719 .setActions(actions)
720 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
721
722 //Don't push the first flow entry. We need to push entries in the
723 //first switch based on IP prefix which we don't know yet.
724 for (int i = 1; i < flowEntries.size(); i++){
725 FlowEntry flowEntry = flowEntries.get(i);
726
727 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200728 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700729 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
730 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
731
732 fm.setMatch(match);
733
734 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
735
736 if (sw == null){
737 log.warn("Switch not found when pushing flow mod");
738 continue;
739 }
740
Jonathan Hart309889c2013-08-13 23:26:24 +1200741 flowMods.add(new PushedFlowMod(sw.getId(), fm));
742
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700743 List<OFMessage> msglist = new ArrayList<OFMessage>();
744 msglist.add(fm);
745 try {
746 sw.write(msglist, null);
747 sw.flush();
748 } catch (IOException e) {
749 log.error("Failure writing flow mod", e);
750 }
751
752 try {
753 fm = fm.clone();
754 } catch (CloneNotSupportedException e1) {
755 log.error("Failure cloning flow mod", e1);
756 }
757 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200758
759 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700760 }
761
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200762 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200763 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200764 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
765
766 DataPath path = topoRouteService.getShortestPath(
767 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
768
769 if (path == null){
770 log.debug("Unable to compute path for BGP traffic for {}",
771 bgpPeer.getIpAddress());
772 continue;
773 }
774
775 //Set up the flow mod
776 OFFlowMod fm =
777 (OFFlowMod) floodlightProvider.getOFMessageFactory()
778 .getMessage(OFType.FLOW_MOD);
779
780 OFActionOutput action = new OFActionOutput();
781 action.setMaxLength((short)0xffff);
782 List<OFAction> actions = new ArrayList<OFAction>();
783 actions.add(action);
784
785 fm.setIdleTimeout((short)0)
786 .setHardTimeout((short)0)
787 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
788 .setCookie(BGP_COOKIE)
789 .setCommand(OFFlowMod.OFPFC_ADD)
790 .setPriority(SDNIP_PRIORITY)
791 .setActions(actions)
792 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
793
794 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
795 OFMatch forwardMatchSrc = new OFMatch();
796
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200797 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
798 + "/32";
799 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
800 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200801
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200802 //Common match fields
803 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200804 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
805 forwardMatchSrc.setTransportDestination(BGP_PORT);
806 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
807 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
808
809
810 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
811
812 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
813 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
814
815 OFMatch forwardMatchDst = forwardMatchSrc.clone();
816
817 forwardMatchSrc.setTransportSource(BGP_PORT);
818 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
819 forwardMatchDst.setTransportDestination(BGP_PORT);
820 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
821
822 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
823 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
824
825 OFMatch reverseMatchDst = reverseMatchSrc.clone();
826
827 reverseMatchSrc.setTransportSource(BGP_PORT);
828 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
829 reverseMatchDst.setTransportDestination(BGP_PORT);
830 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
831
832 fm.setMatch(forwardMatchSrc);
833
Jonathan Hart38c84932013-08-10 17:49:27 +1200834 OFMatch forwardIcmpMatch = new OFMatch();
835 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
836 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
837 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
838 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
839
840 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
841 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
842 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
843
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200844 for (FlowEntry flowEntry : path.flowEntries()){
845 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
846 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200847 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200848 try {
849 forwardFlowModSrc = fm.clone();
850 forwardFlowModDst = fm.clone();
851 reverseFlowModSrc = fm.clone();
852 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200853 forwardIcmp = fm.clone();
854 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200855 } catch (CloneNotSupportedException e) {
856 log.warn("Clone failed", e);
857 continue;
858 }
859
860 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
861 forwardFlowModSrc.setMatch(forwardMatchSrc);
862 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
863 .setPort(flowEntry.outPort().value());
864
865 forwardMatchDst.setInputPort(flowEntry.inPort().value());
866 forwardFlowModDst.setMatch(forwardMatchDst);
867 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
868 .setPort(flowEntry.outPort().value());
869
870 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
871 reverseFlowModSrc.setMatch(reverseMatchSrc);
872 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
873 .setPort(flowEntry.inPort().value());
874
875 reverseMatchDst.setInputPort(flowEntry.outPort().value());
876 reverseFlowModDst.setMatch(reverseMatchDst);
877 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
878 .setPort(flowEntry.inPort().value());
879
Jonathan Hart38c84932013-08-10 17:49:27 +1200880 ((OFActionOutput)forwardIcmp.getActions().get(0))
881 .setPort(flowEntry.outPort().value());
882 forwardIcmp.setMatch(forwardIcmpMatch);
883
884 ((OFActionOutput)reverseIcmp.getActions().get(0))
885 .setPort(flowEntry.inPort().value());
886 reverseIcmp.setMatch(reverseIcmpMatch);
887
888
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200889 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
890
Jonathan Hart38c84932013-08-10 17:49:27 +1200891 if (sw == null) {
892 log.warn("Switch not found when pushing BGP paths");
893 return;
894 }
895
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200896 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
897 msgList.add(forwardFlowModSrc);
898 msgList.add(forwardFlowModDst);
899 msgList.add(reverseFlowModSrc);
900 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +1200901 msgList.add(forwardIcmp);
902 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200903
904 try {
905 sw.write(msgList, null);
906 sw.flush();
907 } catch (IOException e) {
908 log.error("Failure writing flow mod", e);
909 }
910 }
911 }
912 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200913
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200914 @Override
915 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
916 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
917 MACAddress.valueOf(macAddress).toString());
918
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200919 /*
920 * We synchronize on this to prevent changes to the ptree while we're pushing
921 * flows to the switches. If the ptree changes, the ptree and switches
922 * could get out of sync.
923 */
924 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200925 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200926
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200927 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200928 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200929 path.getDstIpAddress().getHostAddress(),
Jonathan Hart309889c2013-08-13 23:26:24 +1200930 MACAddress.valueOf(macAddress),
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200931 path.getDstInterface().getSwitchPort()});
932 //These paths should always be to BGP peers. Paths to non-peers are
933 //handled once the first prefix is ready to push
934 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200935 //A path already got pushed to this endpoint while we were waiting
936 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200937 if (path.isPermanent()) {
938 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200939 }
940 }
941 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200942 setUpDataPath(path, MACAddress.valueOf(macAddress));
943 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200944 }
945 }
946
Jonathan Hart309889c2013-08-13 23:26:24 +1200947 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
948
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200949 for (RibUpdate update : prefixesToPush) {
950 //These will always be adds
951
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200952 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200953 if (rib != null && rib.equals(update.getRibEntry())) {
954 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200955 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200956 //We only push prefix flows if the prefix is still in the ptree
957 //and the next hop is the same as our update. The prefix could
958 //have been removed while we were waiting for the ARP, or the
959 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200960 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200961 } else {
962 log.debug("Received ARP response, but {},{} is no longer in ptree",
963 update.getPrefix(), update.getRibEntry());
964 }
965 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200966 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200967 }
968
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200969 private void beginRouting(){
970 log.debug("Topology is now ready, beginning routing function");
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200971 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200972 setupFullMesh();
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200973
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200974 bgpUpdatesExecutor.execute(new Runnable() {
975 @Override
976 public void run() {
977 doUpdatesThread();
978 }
979 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200980 }
981
982 private void checkSwitchesConnected(){
983 for (String dpid : switches){
984 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
985 log.debug("Not all switches are here yet");
986 return;
987 }
988 }
989 switchesConnected = true;
990 }
991
Jonathan Hartc824ad02013-07-03 15:58:45 +1200992 //Actually we only need to go half way round to verify full mesh connectivity
993 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200994 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200995 for (Interface dstInterface : interfaces.values()) {
996 for (Interface srcInterface : interfaces.values()) {
997 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200998 continue;
999 }
1000
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001001 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001002 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001003
1004 if (shortestPath == null){
1005 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001006 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001007 return;
1008 }
1009 }
1010 }
1011 topologyReady = true;
1012 }
1013
1014 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001015 if (!switchesConnected){
1016 checkSwitchesConnected();
1017 }
1018 boolean oldTopologyReadyStatus = topologyReady;
1019 if (switchesConnected && !topologyReady){
1020 checkTopologyReady();
1021 }
1022 if (!oldTopologyReadyStatus && topologyReady){
1023 beginRouting();
1024 }
1025 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001026
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001027 private void doUpdatesThread() {
1028 boolean interrupted = false;
1029 try {
1030 while (true) {
1031 try {
1032 RibUpdate update = ribUpdates.take();
1033 switch (update.getOperation()){
1034 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001035 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001036 break;
1037 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001038 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001039 break;
1040 }
1041 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001042 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001043 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001044 } catch (Exception e) {
1045 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001046 }
1047 }
1048 } finally {
1049 if (interrupted) {
1050 Thread.currentThread().interrupt();
1051 }
1052 }
1053 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001054
1055 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001056 public void topologyChanged() {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001057 boolean refreshNeeded = false;
1058 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1059 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1060 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001061 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001062 refreshNeeded = true;
1063 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001064
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001065 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001066
Jonathan Hart98957bf2013-07-01 14:49:24 +12001067 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1068 synchronized (linkUpdates) {
1069 linkUpdates.add(ldu);
1070 }
1071 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001072 }
1073
1074 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001075 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001076 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001077 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001078}