blob: ceab262676cc71a942c0cbea8401bfb34a48b2d5 [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 Harta23ffdb2013-08-14 14:36:54 +1200582 Path path = prefixToPath.get(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200583
584 if (path == null) {
585 log.error("No path found for non-peer path");
586 }
587
588 path.decrementUsers();
589 log.debug("users {}, permanent {}", path.getUsers(), path.isPermanent());
590 if (path.getUsers() <= 0 && !path.isPermanent()) {
591 deletePath(path);
592 }
593 }
594 }
595
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200596 private void deletePrefixFlows(Prefix prefix) {
597 Collection<PushedFlowMod> pushedFlowMods
598 = pushedFlows.removeAll(prefix);
599
600 for (PushedFlowMod pfm : pushedFlowMods) {
601 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
602 new Object[] {HexString.toHexString(pfm.getDpid()),
603 pfm.getFlowMod().getMatch().getNetworkDestination() +
604 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
605 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
606 .getDataLayerAddress())});
607
608 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
609 }
610 }
611
612 private void deletePath(Path path) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200613 for (PushedFlowMod pfm : path.getFlowMods()) {
614 log.debug("Pushing a DELETE flow mod to {}, dst MAC {}",
615 new Object[] {HexString.toHexString(pfm.getDpid()),
616 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
617 });
618
619 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
620 }
621 }
622
623 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
624 addFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
625 .setOutPort(OFPort.OFPP_NONE)
626 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
627
628 addFlowMod.getActions().clear();
629
630 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
631 if (sw == null) {
632 log.warn("Switch not found when pushing delete flow mod");
633 return;
634 }
635
636 try {
637 sw.write(addFlowMod, null);
638 sw.flush();
639 } catch (IOException e) {
640 log.error("Failure writing flow mod", e);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200641 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200642 }
643
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200644 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200645 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200646
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700647 /*
648 * On startup we need to calculate a full mesh of paths between all gateway
649 * switches
650 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200651 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700652 //For each border router, calculate and install a path from every other
653 //border switch to said border router. However, don't install the entry
654 //in to the first hop switch, as we need to install an entry to rewrite
655 //for each prefix received. This will be done later when prefixes have
656 //actually been received.
657
Jonathan Hartc824ad02013-07-03 15:58:45 +1200658 for (BgpPeer peer : bgpPeers.values()) {
659 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200660
Jonathan Hart309889c2013-08-13 23:26:24 +1200661 //We know there's not already a Path here pushed, because this is
662 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200663 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200664 path.setPermanent();
665
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200666 //See if we know the MAC address of the peer. If not we can't
667 //do anything until we learn it
668 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
669 if (mac == null) {
670 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
671 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200672 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700673
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200674 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
675 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700676 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200677
678 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200679 setUpDataPath(path, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700680 }
681 }
682
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200683 private void setUpDataPath(Path path, MACAddress dstMacAddress) {
684 calculateAndPushPath(path, dstMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200685 }
686
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200687 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200688 Interface dstInterface = path.getDstInterface();
689
690 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
691
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200692 for (Interface srcInterface : interfaces.values()) {
693 if (dstInterface.equals(srcInterface.getName())){
694 continue;
695 }
696
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200697 DataPath shortestPath;
698 if (topoRouteTopology == null) {
699 log.debug("Using database topo");
700 shortestPath = topoRouteService.getShortestPath(
701 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
702 }
703 else {
704 log.debug("Using prepared topo");
705 shortestPath = topoRouteService.getTopoShortestPath(topoRouteTopology,
706 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
707 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200708
709 if (shortestPath == null){
710 log.debug("Shortest path between {} and {} not found",
711 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
712 return; // just quit here?
713 }
714
Jonathan Hart309889c2013-08-13 23:26:24 +1200715 pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200716 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200717
718 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200719 }
720
Jonathan Hart309889c2013-08-13 23:26:24 +1200721 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
722 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
723
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700724 //Set up the flow mod
725 OFFlowMod fm =
726 (OFFlowMod) floodlightProvider.getOFMessageFactory()
727 .getMessage(OFType.FLOW_MOD);
728
729 OFActionOutput action = new OFActionOutput();
730 action.setMaxLength((short)0xffff);
731 List<OFAction> actions = new ArrayList<OFAction>();
732 actions.add(action);
733
734 fm.setIdleTimeout((short)0)
735 .setHardTimeout((short)0)
736 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
737 .setCookie(L2_FWD_COOKIE)
738 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700739 .setActions(actions)
740 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
741
742 //Don't push the first flow entry. We need to push entries in the
743 //first switch based on IP prefix which we don't know yet.
744 for (int i = 1; i < flowEntries.size(); i++){
745 FlowEntry flowEntry = flowEntries.get(i);
746
747 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200748 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700749 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
750 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
751
752 fm.setMatch(match);
753
754 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
755
756 if (sw == null){
757 log.warn("Switch not found when pushing flow mod");
758 continue;
759 }
760
Jonathan Hart309889c2013-08-13 23:26:24 +1200761 flowMods.add(new PushedFlowMod(sw.getId(), fm));
762
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700763 List<OFMessage> msglist = new ArrayList<OFMessage>();
764 msglist.add(fm);
765 try {
766 sw.write(msglist, null);
767 sw.flush();
768 } catch (IOException e) {
769 log.error("Failure writing flow mod", e);
770 }
771
772 try {
773 fm = fm.clone();
774 } catch (CloneNotSupportedException e1) {
775 log.error("Failure cloning flow mod", e1);
776 }
777 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200778
779 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700780 }
781
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200782 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200783 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200784 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
785
786 DataPath path = topoRouteService.getShortestPath(
787 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
788
789 if (path == null){
790 log.debug("Unable to compute path for BGP traffic for {}",
791 bgpPeer.getIpAddress());
792 continue;
793 }
794
795 //Set up the flow mod
796 OFFlowMod fm =
797 (OFFlowMod) floodlightProvider.getOFMessageFactory()
798 .getMessage(OFType.FLOW_MOD);
799
800 OFActionOutput action = new OFActionOutput();
801 action.setMaxLength((short)0xffff);
802 List<OFAction> actions = new ArrayList<OFAction>();
803 actions.add(action);
804
805 fm.setIdleTimeout((short)0)
806 .setHardTimeout((short)0)
807 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
808 .setCookie(BGP_COOKIE)
809 .setCommand(OFFlowMod.OFPFC_ADD)
810 .setPriority(SDNIP_PRIORITY)
811 .setActions(actions)
812 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
813
814 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
815 OFMatch forwardMatchSrc = new OFMatch();
816
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200817 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
818 + "/32";
819 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
820 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200821
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200822 //Common match fields
823 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200824 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
825 forwardMatchSrc.setTransportDestination(BGP_PORT);
826 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
827 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
828
829
830 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
831
832 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
833 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
834
835 OFMatch forwardMatchDst = forwardMatchSrc.clone();
836
837 forwardMatchSrc.setTransportSource(BGP_PORT);
838 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
839 forwardMatchDst.setTransportDestination(BGP_PORT);
840 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
841
842 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
843 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
844
845 OFMatch reverseMatchDst = reverseMatchSrc.clone();
846
847 reverseMatchSrc.setTransportSource(BGP_PORT);
848 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
849 reverseMatchDst.setTransportDestination(BGP_PORT);
850 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
851
852 fm.setMatch(forwardMatchSrc);
853
Jonathan Hart38c84932013-08-10 17:49:27 +1200854 OFMatch forwardIcmpMatch = new OFMatch();
855 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
856 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
857 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
858 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
859
860 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
861 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
862 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
863
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200864 for (FlowEntry flowEntry : path.flowEntries()){
865 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
866 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200867 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200868 try {
869 forwardFlowModSrc = fm.clone();
870 forwardFlowModDst = fm.clone();
871 reverseFlowModSrc = fm.clone();
872 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200873 forwardIcmp = fm.clone();
874 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200875 } catch (CloneNotSupportedException e) {
876 log.warn("Clone failed", e);
877 continue;
878 }
879
880 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
881 forwardFlowModSrc.setMatch(forwardMatchSrc);
882 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
883 .setPort(flowEntry.outPort().value());
884
885 forwardMatchDst.setInputPort(flowEntry.inPort().value());
886 forwardFlowModDst.setMatch(forwardMatchDst);
887 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
888 .setPort(flowEntry.outPort().value());
889
890 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
891 reverseFlowModSrc.setMatch(reverseMatchSrc);
892 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
893 .setPort(flowEntry.inPort().value());
894
895 reverseMatchDst.setInputPort(flowEntry.outPort().value());
896 reverseFlowModDst.setMatch(reverseMatchDst);
897 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
898 .setPort(flowEntry.inPort().value());
899
Jonathan Hart38c84932013-08-10 17:49:27 +1200900 ((OFActionOutput)forwardIcmp.getActions().get(0))
901 .setPort(flowEntry.outPort().value());
902 forwardIcmp.setMatch(forwardIcmpMatch);
903
904 ((OFActionOutput)reverseIcmp.getActions().get(0))
905 .setPort(flowEntry.inPort().value());
906 reverseIcmp.setMatch(reverseIcmpMatch);
907
908
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200909 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
910
Jonathan Hart38c84932013-08-10 17:49:27 +1200911 if (sw == null) {
912 log.warn("Switch not found when pushing BGP paths");
913 return;
914 }
915
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200916 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
917 msgList.add(forwardFlowModSrc);
918 msgList.add(forwardFlowModDst);
919 msgList.add(reverseFlowModSrc);
920 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +1200921 msgList.add(forwardIcmp);
922 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200923
924 try {
925 sw.write(msgList, null);
926 sw.flush();
927 } catch (IOException e) {
928 log.error("Failure writing flow mod", e);
929 }
930 }
931 }
932 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200933
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200934 @Override
935 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
936 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
937 MACAddress.valueOf(macAddress).toString());
938
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200939 /*
940 * We synchronize on this to prevent changes to the ptree while we're pushing
941 * flows to the switches. If the ptree changes, the ptree and switches
942 * could get out of sync.
943 */
944 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200945 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200946
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200947 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200948 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200949 path.getDstIpAddress().getHostAddress(),
Jonathan Hart309889c2013-08-13 23:26:24 +1200950 MACAddress.valueOf(macAddress),
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200951 path.getDstInterface().getSwitchPort()});
952 //These paths should always be to BGP peers. Paths to non-peers are
953 //handled once the first prefix is ready to push
954 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200955 //A path already got pushed to this endpoint while we were waiting
956 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200957 if (path.isPermanent()) {
958 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200959 }
960 }
961 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200962 setUpDataPath(path, MACAddress.valueOf(macAddress));
963 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200964 }
965 }
966
Jonathan Hart309889c2013-08-13 23:26:24 +1200967 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
968
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200969 for (RibUpdate update : prefixesToPush) {
970 //These will always be adds
971
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200972 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200973 if (rib != null && rib.equals(update.getRibEntry())) {
974 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200975 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200976 //We only push prefix flows if the prefix is still in the ptree
977 //and the next hop is the same as our update. The prefix could
978 //have been removed while we were waiting for the ARP, or the
979 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200980 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200981 } else {
982 log.debug("Received ARP response, but {},{} is no longer in ptree",
983 update.getPrefix(), update.getRibEntry());
984 }
985 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200986 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200987 }
988
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200989 private void beginRouting(){
990 log.debug("Topology is now ready, beginning routing function");
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200991 topoRouteTopology = topoRouteService.prepareShortestPathTopo();
992
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200993 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200994 setupFullMesh();
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200995
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200996 bgpUpdatesExecutor.execute(new Runnable() {
997 @Override
998 public void run() {
999 doUpdatesThread();
1000 }
1001 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001002 }
1003
1004 private void checkSwitchesConnected(){
1005 for (String dpid : switches){
1006 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1007 log.debug("Not all switches are here yet");
1008 return;
1009 }
1010 }
1011 switchesConnected = true;
1012 }
1013
Jonathan Hartc824ad02013-07-03 15:58:45 +12001014 //Actually we only need to go half way round to verify full mesh connectivity
1015 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001016 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001017 for (Interface dstInterface : interfaces.values()) {
1018 for (Interface srcInterface : interfaces.values()) {
1019 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001020 continue;
1021 }
1022
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001023 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001024 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001025
1026 if (shortestPath == null){
1027 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001028 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001029 return;
1030 }
1031 }
1032 }
1033 topologyReady = true;
1034 }
1035
1036 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001037 if (!switchesConnected){
1038 checkSwitchesConnected();
1039 }
1040 boolean oldTopologyReadyStatus = topologyReady;
1041 if (switchesConnected && !topologyReady){
1042 checkTopologyReady();
1043 }
1044 if (!oldTopologyReadyStatus && topologyReady){
1045 beginRouting();
1046 }
1047 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001048
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001049 private void doUpdatesThread() {
1050 boolean interrupted = false;
1051 try {
1052 while (true) {
1053 try {
1054 RibUpdate update = ribUpdates.take();
1055 switch (update.getOperation()){
1056 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001057 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001058 break;
1059 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001060 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001061 break;
1062 }
1063 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001064 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001065 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001066 } catch (Exception e) {
1067 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001068 }
1069 }
1070 } finally {
1071 if (interrupted) {
1072 Thread.currentThread().interrupt();
1073 }
1074 }
1075 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001076
1077 @Override
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001078 public void topologyChanged() {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001079 boolean refreshNeeded = false;
1080 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1081 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1082 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001083 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001084 refreshNeeded = true;
1085 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001086
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001087 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001088
Jonathan Hart98957bf2013-07-01 14:49:24 +12001089 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1090 synchronized (linkUpdates) {
1091 linkUpdates.add(ldu);
1092 }
1093 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001094 }
1095
1096 if (refreshNeeded){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001097 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001098 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001099 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001100}