blob: 108b46ad61150612482a6fc6dce7721ff15e4a2b [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 Hartdefa44d2013-08-15 19:51:13 +1200136
137 protected volatile Map<Long, ?> topoRouteTopology = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200138
Jonathan Hart98957bf2013-07-01 14:49:24 +1200139 protected class TopologyChangeDetector implements Runnable {
140 @Override
141 public void run() {
142 log.debug("Running topology change detection task");
143 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200144 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200145 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
146
147 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200148
149 Iterator<LDUpdate> it = linkUpdates.iterator();
150 while (it.hasNext()){
151 LDUpdate ldu = it.next();
152 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
153 ldu.getDst(), ldu.getDstPort());
154
155 if (activeLinks.contains(l)){
156 log.debug("Not found: {}", l);
157 it.remove();
158 }
159 }
160 }
161
162 if (linkUpdates.isEmpty()){
163 //All updates have been seen in network map.
164 //We can check if topology is ready
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200165 log.debug("No known changes outstanding. Checking topology now");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200166 checkStatus();
167 }
168 else {
169 //We know of some link updates that haven't propagated to the database yet
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200170 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
Jonathan Hart98957bf2013-07-01 14:49:24 +1200171 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
172 }
173 }
174 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700175
Jonathan Hartd1f23252013-06-13 15:17:05 +1200176 private void readGatewaysConfiguration(String gatewaysFilename){
177 File gatewaysFile = new File(gatewaysFilename);
178 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700179
Jonathan Hartd1f23252013-06-13 15:17:05 +1200180 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200181 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
182
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200183 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200184 interfaces = new HashMap<String, Interface>();
185 for (Interface intf : config.getInterfaces()){
186 interfaces.put(intf.getName(), intf);
187 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200188 bgpPeers = new HashMap<InetAddress, BgpPeer>();
189 for (BgpPeer peer : config.getPeers()){
190 bgpPeers.put(peer.getIpAddress(), peer);
191 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200192
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200193 bgpdAttachmentPoint = new SwitchPort(
194 new Dpid(config.getBgpdAttachmentDpid()),
195 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200196
Jonathan Hart2f790d22013-08-15 14:01:24 +1200197 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200198 } catch (JsonParseException e) {
199 log.error("Error in JSON file", e);
200 System.exit(1);
201 } catch (JsonMappingException e) {
202 log.error("Error in JSON file", e);
203 System.exit(1);
204 } catch (IOException e) {
205 log.error("Error reading JSON file", e);
206 System.exit(1);
207 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200208
209 //Populate the interface Patricia Trie
210 for (Interface intf : interfaces.values()) {
211 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
212 interfacePtrie.put(prefix, intf);
213 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700214 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800215
216 @Override
217 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700218 Collection<Class<? extends IFloodlightService>> l
219 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800220 l.add(IBgpRouteService.class);
221 return l;
222 }
223
224 @Override
225 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700226 Map<Class<? extends IFloodlightService>, IFloodlightService> m
227 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800228 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800229 return m;
230 }
231
pingping-lina2cbfad2013-03-07 08:39:21 +0800232 @Override
233 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700234 Collection<Class<? extends IFloodlightService>> l
235 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800236 l.add(IFloodlightProviderService.class);
237 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700238 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800239 return l;
240 }
241
242 @Override
243 public void init(FloodlightModuleContext context)
244 throws FloodlightModuleException {
245
Jonathan Hart29b972d2013-08-12 23:43:51 +1200246 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200247 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200248
249 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200250
pingping-lina2cbfad2013-03-07 08:39:21 +0800251 // Register floodlight provider and REST handler.
252 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800253 topology = context.getServiceImpl(ITopologyService.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 Hart2f790d22013-08-15 14:01:24 +1200258 proxyArp = new ProxyArpManager(floodlightProvider, topology);
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 Hart2f790d22013-08-15 14:01:24 +1200303
304 proxyArp.setL3Mode(interfacePtrie, bgpdMacAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200305 }
306
307 @Override
308 public void startUp(FloodlightModuleContext context) {
309 restApi.addRestletRoutable(new BgpRouteWebRoutable());
310 topology.addListener(this);
311
Jonathan Hart2f790d22013-08-15 14:01:24 +1200312 proxyArp.startUp();
313
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200314 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
315
316 //Retrieve the RIB from BGPd during startup
317 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800318 }
319
Jonathan Hart29b972d2013-08-12 23:43:51 +1200320 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800321 return ptree;
322 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700323
324 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200325 ptree = new PatriciaTrie<RibEntry>(32);
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 getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700329 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800330 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700331
pingping-line2a09ca2013-03-23 09:33:58 +0800332 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700333 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800334 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800335
Jonathan Hart61ba9372013-05-19 20:10:29 -0700336 private void retrieveRib(){
337 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
338 String response = RestClient.get(url);
339
340 if (response.equals("")){
341 return;
342 }
343
344 response = response.replaceAll("\"", "'");
345 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
346 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
347 String router_id = jsonObj.getString("router-id");
348
349 int size = rib_json_array.size();
350
351 log.info("Retrived RIB of {} entries from BGPd", size);
352
353 for (int j = 0; j < size; j++) {
354 JSONObject second_json_object = rib_json_array.getJSONObject(j);
355 String prefix = second_json_object.getString("prefix");
356 String nexthop = second_json_object.getString("nexthop");
357
358 //insert each rib entry into the local rib;
359 String[] substring = prefix.split("/");
360 String prefix1 = substring[0];
361 String mask1 = substring[1];
362
363 Prefix p;
364 try {
365 p = new Prefix(prefix1, Integer.valueOf(mask1));
366 } catch (NumberFormatException e) {
367 log.warn("Wrong mask format in RIB JSON: {}", mask1);
368 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200369 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700370 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
371 continue;
372 }
373
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200374 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200375
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200376 try {
377 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
378 } catch (InterruptedException e) {
379 log.debug("Interrupted while pushing onto update queue");
380 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700381 }
382 }
383
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200384 @Override
385 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200386 try {
387 ribUpdates.put(update);
388 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200389 log.debug("Interrupted while putting on ribUpdates queue", e);
390 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200391 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200392 }
393
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200394 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200395 Prefix prefix = update.getPrefix();
396
Jonathan Hart9ea31212013-08-12 21:40:34 +1200397 log.debug("Processing prefix add {}", prefix);
398
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200399 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200400
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200401 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200402 //There was an existing nexthop for this prefix. This update supersedes that,
403 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200404 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200405 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200406
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200407 if (update.getRibEntry().getNextHop().equals(
408 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200409 //Route originated by SDN domain
410 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200411 log.debug("Own route {} to {}", prefix,
412 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200413 return;
414 }
415
416 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200417 }
418
Jonathan Hart309889c2013-08-13 23:26:24 +1200419 private void _processRibAdd(RibUpdate update) {
420 Prefix prefix = update.getPrefix();
421 RibEntry rib = update.getRibEntry();
422
423 InetAddress dstIpAddress = rib.getNextHop();
424
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200425 //See if we know the MAC address of the next hop
Jonathan Hart309889c2013-08-13 23:26:24 +1200426 byte[] nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200427
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200428 //Find the attachment point (egress interface) of the next hop
429 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200430 if (bgpPeers.containsKey(dstIpAddress)) {
431 //Route to a peer
432 log.debug("Route to peer {}", dstIpAddress);
433 BgpPeer peer = bgpPeers.get(dstIpAddress);
434 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200435 }
436 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200437 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200438 log.debug("Route to non-peer {}", dstIpAddress);
439 egressInterface = interfacePtrie.match(
440 new Prefix(dstIpAddress.getAddress(), 32));
441 if (egressInterface == null) {
442 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
443 return;
444 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200445 }
446
447 if (nextHopMacAddress == null) {
448 prefixesWaitingOnArp.put(dstIpAddress,
449 new RibUpdate(Operation.UPDATE, prefix, rib));
450 proxyArp.sendArpRequest(dstIpAddress, this, true);
451 return;
452 }
453 else {
454 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200455 //If the prefix is for a non-peer we need to ensure there's a path,
456 //and push one if there isn't.
457 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200458 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200459 path = new Path(egressInterface, dstIpAddress);
460 setUpDataPath(path, MACAddress.valueOf(nextHopMacAddress));
Jonathan Hart309889c2013-08-13 23:26:24 +1200461 pushedPaths.put(dstIpAddress, path);
462 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200463
464 path.incrementUsers();
465 prefixToPath.put(prefix, path);
466 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200467
468 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200469 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
470 }
471 }
472
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200473 private void addPrefixFlows(Prefix prefix, Interface egressInterface, byte[] nextHopMacAddress) {
474 log.debug("Adding flows for prefix {} added, next hop mac {}",
475 prefix, HexString.toHexString(nextHopMacAddress));
476
477 //Add a flow to rewrite mac for this prefix to all other border switches
478 for (Interface srcInterface : interfaces.values()) {
479 if (srcInterface == egressInterface) {
480 //Don't push a flow for the switch where this peer is attached
481 continue;
482 }
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200483
484
485 DataPath shortestPath;
486 if (topoRouteTopology == null) {
487 shortestPath = topoRouteService.getShortestPath(
488 srcInterface.getSwitchPort(),
489 egressInterface.getSwitchPort());
490 }
491 else {
492 shortestPath = topoRouteService.getTopoShortestPath(
493 topoRouteTopology, srcInterface.getSwitchPort(),
494 egressInterface.getSwitchPort());
495 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200496
497 if (shortestPath == null){
498 log.debug("Shortest path between {} and {} not found",
499 srcInterface.getSwitchPort(),
500 egressInterface.getSwitchPort());
501 return; // just quit here?
502 }
503
504 //Set up the flow mod
505 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
506 .getMessage(OFType.FLOW_MOD);
507
508 fm.setIdleTimeout((short)0)
509 .setHardTimeout((short)0)
510 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
511 .setCookie(MAC_RW_COOKIE)
512 .setCommand(OFFlowMod.OFPFC_ADD)
513 .setPriority(SDNIP_PRIORITY)
514 .setLengthU(OFFlowMod.MINIMUM_LENGTH
515 + OFActionDataLayerDestination.MINIMUM_LENGTH
516 + OFActionOutput.MINIMUM_LENGTH);
517
518 OFMatch match = new OFMatch();
519 match.setDataLayerType(Ethernet.TYPE_IPv4);
520 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
521
522 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
523 fm.setMatch(match);
524
525 //Set up MAC rewrite action
526 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
527 macRewriteAction.setDataLayerAddress(nextHopMacAddress);
528
529 //Set up output action
530 OFActionOutput outputAction = new OFActionOutput();
531 outputAction.setMaxLength((short)0xffff);
532 Port outputPort = shortestPath.flowEntries().get(0).outPort();
533 outputAction.setPort(outputPort.value());
534
535 List<OFAction> actions = new ArrayList<OFAction>();
536 actions.add(macRewriteAction);
537 actions.add(outputAction);
538 fm.setActions(actions);
539
540 //Write to switch
541 IOFSwitch sw = floodlightProvider.getSwitches()
542 .get(srcInterface.getDpid());
543
544 if (sw == null){
545 log.warn("Switch not found when pushing flow mod");
546 continue;
547 }
548
549 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
550
551 List<OFMessage> msglist = new ArrayList<OFMessage>();
552 msglist.add(fm);
553 try {
554 sw.write(msglist, null);
555 sw.flush();
556 } catch (IOException e) {
557 log.error("Failure writing flow mod", e);
558 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200559 }
560 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200561
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200562 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200563 Prefix prefix = update.getPrefix();
564
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200565 if (ptree.remove(prefix, update.getRibEntry())) {
566 /*
567 * Only delete flows if an entry was actually removed from the trie.
568 * If no entry was removed, the <prefix, nexthop> wasn't there so
569 * it's probably already been removed and we don't need to do anything
570 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200571 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200572 }
573 }
574
575 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
576 deletePrefixFlows(prefix);
577
578 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
579 log.debug("is peer {}", bgpPeers.containsKey(ribEntry.getNextHop()));
580 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
581 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200582 //Path path = prefixToPath.get(prefix);
583 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200584
585 if (path == null) {
586 log.error("No path found for non-peer path");
587 }
588
589 path.decrementUsers();
590 log.debug("users {}, permanent {}", path.getUsers(), path.isPermanent());
591 if (path.getUsers() <= 0 && !path.isPermanent()) {
592 deletePath(path);
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200593 pushedPaths.remove(path.getDstIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200594 }
595 }
596 }
597
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200598 private void deletePrefixFlows(Prefix prefix) {
599 Collection<PushedFlowMod> pushedFlowMods
600 = pushedFlows.removeAll(prefix);
601
602 for (PushedFlowMod pfm : pushedFlowMods) {
603 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
604 new Object[] {HexString.toHexString(pfm.getDpid()),
605 pfm.getFlowMod().getMatch().getNetworkDestination() +
606 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
607 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
608 .getDataLayerAddress())});
609
610 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
611 }
612 }
613
614 private void deletePath(Path path) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200615 for (PushedFlowMod pfm : path.getFlowMods()) {
616 log.debug("Pushing a DELETE flow mod to {}, dst MAC {}",
617 new Object[] {HexString.toHexString(pfm.getDpid()),
618 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
619 });
620
621 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
622 }
623 }
624
625 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
626 addFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
627 .setOutPort(OFPort.OFPP_NONE)
628 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
629
630 addFlowMod.getActions().clear();
631
632 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
633 if (sw == null) {
634 log.warn("Switch not found when pushing delete flow mod");
635 return;
636 }
637
638 try {
639 sw.write(addFlowMod, null);
640 sw.flush();
641 } catch (IOException e) {
642 log.error("Failure writing flow mod", e);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200643 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200644 }
645
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200646 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200647 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200648
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700649 /*
650 * On startup we need to calculate a full mesh of paths between all gateway
651 * switches
652 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200653 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700654 //For each border router, calculate and install a path from every other
655 //border switch to said border router. However, don't install the entry
656 //in to the first hop switch, as we need to install an entry to rewrite
657 //for each prefix received. This will be done later when prefixes have
658 //actually been received.
659
Jonathan Hartc824ad02013-07-03 15:58:45 +1200660 for (BgpPeer peer : bgpPeers.values()) {
661 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200662
Jonathan Hart309889c2013-08-13 23:26:24 +1200663 //We know there's not already a Path here pushed, because this is
664 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200665 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200666 path.setPermanent();
667
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200668 //See if we know the MAC address of the peer. If not we can't
669 //do anything until we learn it
670 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
671 if (mac == null) {
672 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
673 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200674 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700675
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200676 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
677 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700678 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200679
680 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200681 setUpDataPath(path, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700682 }
683 }
684
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200685 private void setUpDataPath(Path path, MACAddress dstMacAddress) {
686 calculateAndPushPath(path, dstMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200687 }
688
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200689 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200690 Interface dstInterface = path.getDstInterface();
691
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200692 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
693 dstMacAddress);
694
Jonathan Hart309889c2013-08-13 23:26:24 +1200695 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
696
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200697 for (Interface srcInterface : interfaces.values()) {
698 if (dstInterface.equals(srcInterface.getName())){
699 continue;
700 }
701
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200702 DataPath shortestPath;
703 if (topoRouteTopology == null) {
704 log.debug("Using database topo");
705 shortestPath = topoRouteService.getShortestPath(
706 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
707 }
708 else {
709 log.debug("Using prepared topo");
710 shortestPath = topoRouteService.getTopoShortestPath(topoRouteTopology,
711 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
712 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200713
714 if (shortestPath == null){
715 log.debug("Shortest path between {} and {} not found",
716 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
717 return; // just quit here?
718 }
719
Jonathan Hart309889c2013-08-13 23:26:24 +1200720 pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200721 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200722
723 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200724 }
725
Jonathan Hart309889c2013-08-13 23:26:24 +1200726 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
727 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
728
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700729 //Set up the flow mod
730 OFFlowMod fm =
731 (OFFlowMod) floodlightProvider.getOFMessageFactory()
732 .getMessage(OFType.FLOW_MOD);
733
734 OFActionOutput action = new OFActionOutput();
735 action.setMaxLength((short)0xffff);
736 List<OFAction> actions = new ArrayList<OFAction>();
737 actions.add(action);
738
739 fm.setIdleTimeout((short)0)
740 .setHardTimeout((short)0)
741 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
742 .setCookie(L2_FWD_COOKIE)
743 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700744 .setActions(actions)
745 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
746
747 //Don't push the first flow entry. We need to push entries in the
748 //first switch based on IP prefix which we don't know yet.
749 for (int i = 1; i < flowEntries.size(); i++){
750 FlowEntry flowEntry = flowEntries.get(i);
751
752 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200753 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700754 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
755 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
756
757 fm.setMatch(match);
758
759 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
760
761 if (sw == null){
762 log.warn("Switch not found when pushing flow mod");
763 continue;
764 }
765
Jonathan Hart309889c2013-08-13 23:26:24 +1200766 flowMods.add(new PushedFlowMod(sw.getId(), fm));
767
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700768 List<OFMessage> msglist = new ArrayList<OFMessage>();
769 msglist.add(fm);
770 try {
771 sw.write(msglist, null);
772 sw.flush();
773 } catch (IOException e) {
774 log.error("Failure writing flow mod", e);
775 }
776
777 try {
778 fm = fm.clone();
779 } catch (CloneNotSupportedException e1) {
780 log.error("Failure cloning flow mod", e1);
781 }
782 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200783
784 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700785 }
786
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200787 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200788 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200789 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
790
791 DataPath path = topoRouteService.getShortestPath(
792 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
793
794 if (path == null){
795 log.debug("Unable to compute path for BGP traffic for {}",
796 bgpPeer.getIpAddress());
797 continue;
798 }
799
800 //Set up the flow mod
801 OFFlowMod fm =
802 (OFFlowMod) floodlightProvider.getOFMessageFactory()
803 .getMessage(OFType.FLOW_MOD);
804
805 OFActionOutput action = new OFActionOutput();
806 action.setMaxLength((short)0xffff);
807 List<OFAction> actions = new ArrayList<OFAction>();
808 actions.add(action);
809
810 fm.setIdleTimeout((short)0)
811 .setHardTimeout((short)0)
812 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
813 .setCookie(BGP_COOKIE)
814 .setCommand(OFFlowMod.OFPFC_ADD)
815 .setPriority(SDNIP_PRIORITY)
816 .setActions(actions)
817 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
818
819 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
820 OFMatch forwardMatchSrc = new OFMatch();
821
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200822 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
823 + "/32";
824 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
825 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200826
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200827 //Common match fields
828 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200829 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
830 forwardMatchSrc.setTransportDestination(BGP_PORT);
831 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
832 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
833
834
835 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
836
837 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
838 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
839
840 OFMatch forwardMatchDst = forwardMatchSrc.clone();
841
842 forwardMatchSrc.setTransportSource(BGP_PORT);
843 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
844 forwardMatchDst.setTransportDestination(BGP_PORT);
845 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
846
847 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
848 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
849
850 OFMatch reverseMatchDst = reverseMatchSrc.clone();
851
852 reverseMatchSrc.setTransportSource(BGP_PORT);
853 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
854 reverseMatchDst.setTransportDestination(BGP_PORT);
855 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
856
857 fm.setMatch(forwardMatchSrc);
858
Jonathan Hart38c84932013-08-10 17:49:27 +1200859 OFMatch forwardIcmpMatch = new OFMatch();
860 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
861 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
862 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
863 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
864
865 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
866 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
867 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
868
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200869 for (FlowEntry flowEntry : path.flowEntries()){
870 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
871 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200872 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200873 try {
874 forwardFlowModSrc = fm.clone();
875 forwardFlowModDst = fm.clone();
876 reverseFlowModSrc = fm.clone();
877 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200878 forwardIcmp = fm.clone();
879 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200880 } catch (CloneNotSupportedException e) {
881 log.warn("Clone failed", e);
882 continue;
883 }
884
885 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
886 forwardFlowModSrc.setMatch(forwardMatchSrc);
887 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
888 .setPort(flowEntry.outPort().value());
889
890 forwardMatchDst.setInputPort(flowEntry.inPort().value());
891 forwardFlowModDst.setMatch(forwardMatchDst);
892 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
893 .setPort(flowEntry.outPort().value());
894
895 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
896 reverseFlowModSrc.setMatch(reverseMatchSrc);
897 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
898 .setPort(flowEntry.inPort().value());
899
900 reverseMatchDst.setInputPort(flowEntry.outPort().value());
901 reverseFlowModDst.setMatch(reverseMatchDst);
902 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
903 .setPort(flowEntry.inPort().value());
904
Jonathan Hart38c84932013-08-10 17:49:27 +1200905 ((OFActionOutput)forwardIcmp.getActions().get(0))
906 .setPort(flowEntry.outPort().value());
907 forwardIcmp.setMatch(forwardIcmpMatch);
908
909 ((OFActionOutput)reverseIcmp.getActions().get(0))
910 .setPort(flowEntry.inPort().value());
911 reverseIcmp.setMatch(reverseIcmpMatch);
912
913
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200914 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
915
Jonathan Hart38c84932013-08-10 17:49:27 +1200916 if (sw == null) {
917 log.warn("Switch not found when pushing BGP paths");
918 return;
919 }
920
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200921 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
922 msgList.add(forwardFlowModSrc);
923 msgList.add(forwardFlowModDst);
924 msgList.add(reverseFlowModSrc);
925 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +1200926 msgList.add(forwardIcmp);
927 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200928
929 try {
930 sw.write(msgList, null);
931 sw.flush();
932 } catch (IOException e) {
933 log.error("Failure writing flow mod", e);
934 }
935 }
936 }
937 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200938
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200939 @Override
940 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
941 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
942 MACAddress.valueOf(macAddress).toString());
943
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200944 /*
945 * We synchronize on this to prevent changes to the ptree while we're pushing
946 * flows to the switches. If the ptree changes, the ptree and switches
947 * could get out of sync.
948 */
949 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200950 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200951
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200952 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200953 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200954 path.getDstIpAddress().getHostAddress(),
Jonathan Hart309889c2013-08-13 23:26:24 +1200955 MACAddress.valueOf(macAddress),
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200956 path.getDstInterface().getSwitchPort()});
957 //These paths should always be to BGP peers. Paths to non-peers are
958 //handled once the first prefix is ready to push
959 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200960 //A path already got pushed to this endpoint while we were waiting
961 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200962 if (path.isPermanent()) {
963 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200964 }
965 }
966 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200967 setUpDataPath(path, MACAddress.valueOf(macAddress));
968 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200969 }
970 }
971
Jonathan Hart309889c2013-08-13 23:26:24 +1200972 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
973
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200974 for (RibUpdate update : prefixesToPush) {
975 //These will always be adds
976
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200977 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200978 if (rib != null && rib.equals(update.getRibEntry())) {
979 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200980 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200981 //We only push prefix flows if the prefix is still in the ptree
982 //and the next hop is the same as our update. The prefix could
983 //have been removed while we were waiting for the ARP, or the
984 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200985 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200986 } else {
987 log.debug("Received ARP response, but {},{} is no longer in ptree",
988 update.getPrefix(), update.getRibEntry());
989 }
990 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200991 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200992 }
993
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200994 private void beginRouting(){
995 log.debug("Topology is now ready, beginning routing function");
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200996 topoRouteTopology = topoRouteService.prepareShortestPathTopo();
997
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200998 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200999 setupFullMesh();
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001000
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001001 bgpUpdatesExecutor.execute(new Runnable() {
1002 @Override
1003 public void run() {
1004 doUpdatesThread();
1005 }
1006 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001007 }
1008
1009 private void checkSwitchesConnected(){
1010 for (String dpid : switches){
1011 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1012 log.debug("Not all switches are here yet");
1013 return;
1014 }
1015 }
1016 switchesConnected = true;
1017 }
1018
Jonathan Hartc824ad02013-07-03 15:58:45 +12001019 //Actually we only need to go half way round to verify full mesh connectivity
1020 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001021 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001022 for (Interface dstInterface : interfaces.values()) {
1023 for (Interface srcInterface : interfaces.values()) {
1024 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001025 continue;
1026 }
1027
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001028 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001029 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001030
1031 if (shortestPath == null){
1032 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001033 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001034 return;
1035 }
1036 }
1037 }
1038 topologyReady = true;
1039 }
1040
1041 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001042 if (!switchesConnected){
1043 checkSwitchesConnected();
1044 }
1045 boolean oldTopologyReadyStatus = topologyReady;
1046 if (switchesConnected && !topologyReady){
1047 checkTopologyReady();
1048 }
1049 if (!oldTopologyReadyStatus && topologyReady){
1050 beginRouting();
1051 }
1052 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001053
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001054 private void doUpdatesThread() {
1055 boolean interrupted = false;
1056 try {
1057 while (true) {
1058 try {
1059 RibUpdate update = ribUpdates.take();
1060 switch (update.getOperation()){
1061 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001062 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001063 break;
1064 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001065 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001066 break;
1067 }
1068 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001069 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001070 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001071 } catch (Exception e) {
1072 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001073 }
1074 }
1075 } finally {
1076 if (interrupted) {
1077 Thread.currentThread().interrupt();
1078 }
1079 }
1080 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001081
1082 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001083 public void topologyChanged() {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001084 boolean refreshNeeded = false;
1085 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1086 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1087 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001088 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001089 refreshNeeded = true;
1090 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001091
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001092 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001093
Jonathan Hart98957bf2013-07-01 14:49:24 +12001094 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1095 synchronized (linkUpdates) {
1096 linkUpdates.add(ldu);
1097 }
1098 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001099 }
1100
1101 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001102 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001103 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001104 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001105}