blob: 2124f784429999eceb7616d5ce300a633cbfd582 [file] [log] [blame]
HIGUCHI Yutaea60e5f2013-06-12 11:10:21 -07001package net.onrc.onos.ofcontroller.bgproute;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
Jonathan Hartd1f23252013-06-13 15:17:05 +12003import java.io.File;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07004import java.io.IOException;
5import java.net.InetAddress;
pingping-lina2cbfad2013-03-07 08:39:21 +08006import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07007import java.util.Collection;
pingping-lina2cbfad2013-03-07 08:39:21 +08008import java.util.HashMap;
Jonathan Hart98957bf2013-07-01 14:49:24 +12009import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070010import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070011import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120012import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120013import java.util.concurrent.BlockingQueue;
14import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120015import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120016import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080019
Jonathan Hart61ba9372013-05-19 20:10:29 -070020import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070021import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart64c0b202013-08-20 15:45:07 +120022import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120027import net.floodlightcontroller.core.util.SingletonTask;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070028import net.floodlightcontroller.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120029import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080030import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120031import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080032import net.floodlightcontroller.topology.ITopologyListener;
33import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120034import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120035import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
Jonathan Hart98957bf2013-07-01 14:49:24 +120036import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070037import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120038import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070039import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
40import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120041import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120042import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070043import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070044import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120045import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070046import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.Port;
48import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080049import net.sf.json.JSONArray;
50import net.sf.json.JSONObject;
51import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080052
Jonathan Hartd1f23252013-06-13 15:17:05 +120053import org.codehaus.jackson.JsonParseException;
54import org.codehaus.jackson.map.JsonMappingException;
55import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070056import org.openflow.protocol.OFFlowMod;
57import org.openflow.protocol.OFMatch;
58import org.openflow.protocol.OFMessage;
59import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120060import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070061import org.openflow.protocol.OFType;
62import org.openflow.protocol.action.OFAction;
63import org.openflow.protocol.action.OFActionDataLayerDestination;
64import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120065import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080066import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
Jonathan Hart4dfc3652013-08-02 20:22:36 +120069import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120070import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120071import com.google.common.collect.Multimaps;
72import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120073import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120074import com.google.common.util.concurrent.ThreadFactoryBuilder;
75
Jonathan Hart1236a9b2013-06-18 22:10:05 +120076public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120077 ITopologyListener, IArpRequester,
78 IOFSwitchListener {
pingping-lina2cbfad2013-03-07 08:39:21 +080079
80 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
81
82 protected IFloodlightProviderService floodlightProvider;
83 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070084 protected ITopoRouteService topoRouteService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070085 protected IRestApiService restApi;
86
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120087 protected ProxyArpManager proxyArp;
88
Jonathan Hart29b972d2013-08-12 23:43:51 +120089 protected IPatriciaTrie<RibEntry> ptree;
Jonathan Hartabf10222013-08-13 10:19:34 +120090 protected IPatriciaTrie<Interface> interfacePtrie;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120091 protected BlockingQueue<RibUpdate> ribUpdates;
92
Jonathan Hart61ba9372013-05-19 20:10:29 -070093 protected String bgpdRestIp;
94 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120095 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070096
97 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
98 //the controller/OS should hand out cookie IDs to prevent conflicts.
99 protected final long APP_COOKIE = 0xa0000000000000L;
100 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
101 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
102 //Cookie for flows in ingress switches that rewrite the MAC address
103 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200104 //Cookie for flows that setup BGP paths
105 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200106 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
107 //need to be higher priority than this otherwise the rewrite may not get done
108 protected final short SDNIP_PRIORITY = 10;
Jonathan Hartc82051c2013-08-24 15:12:20 +1200109 protected final short ARP_PRIORITY = 20;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700110
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200111 protected final short BGP_PORT = 179;
112
Jonathan Hart98957bf2013-07-01 14:49:24 +1200113 protected final int TOPO_DETECTION_WAIT = 2; //seconds
114
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200115 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200116 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200117 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200118 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200119 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart2f790d22013-08-15 14:01:24 +1200120 protected MACAddress bgpdMacAddress;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200121
122 //True when all switches have connected
123 protected volatile boolean switchesConnected = false;
124 //True when we have a full mesh of shortest paths between gateways
125 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200126
Jonathan Hart98957bf2013-07-01 14:49:24 +1200127 protected ArrayList<LDUpdate> linkUpdates;
128 protected SingletonTask topologyChangeDetectorTask;
129
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200130 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200131
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200132 protected Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200133
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200134 protected ExecutorService bgpUpdatesExecutor;
135
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200136 protected Map<InetAddress, Path> pushedPaths;
137 protected Map<Prefix, Path> prefixToPath;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200138 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200139
140 protected volatile Map<Long, ?> topoRouteTopology = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200141
Jonathan Hart98957bf2013-07-01 14:49:24 +1200142 protected class TopologyChangeDetector implements Runnable {
143 @Override
144 public void run() {
145 log.debug("Running topology change detection task");
146 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200147 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200148 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
149
150 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200151
152 Iterator<LDUpdate> it = linkUpdates.iterator();
153 while (it.hasNext()){
154 LDUpdate ldu = it.next();
155 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
156 ldu.getDst(), ldu.getDstPort());
157
158 if (activeLinks.contains(l)){
159 log.debug("Not found: {}", l);
160 it.remove();
161 }
162 }
163 }
164
Jonathan Hart64c0b202013-08-20 15:45:07 +1200165 if (!topologyReady) {
166 if (linkUpdates.isEmpty()){
167 //All updates have been seen in network map.
168 //We can check if topology is ready
169 log.debug("No known changes outstanding. Checking topology now");
170 checkStatus();
171 }
172 else {
173 //We know of some link updates that haven't propagated to the database yet
174 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
175 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
176 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200177 }
178 }
179 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700180
Jonathan Hartd1f23252013-06-13 15:17:05 +1200181 private void readGatewaysConfiguration(String gatewaysFilename){
182 File gatewaysFile = new File(gatewaysFilename);
183 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700184
Jonathan Hartd1f23252013-06-13 15:17:05 +1200185 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200186 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
187
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200188 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200189 interfaces = new HashMap<String, Interface>();
190 for (Interface intf : config.getInterfaces()){
191 interfaces.put(intf.getName(), intf);
192 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200193 bgpPeers = new HashMap<InetAddress, BgpPeer>();
194 for (BgpPeer peer : config.getPeers()){
195 bgpPeers.put(peer.getIpAddress(), peer);
196 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200197
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200198 bgpdAttachmentPoint = new SwitchPort(
199 new Dpid(config.getBgpdAttachmentDpid()),
200 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200201
Jonathan Hart2f790d22013-08-15 14:01:24 +1200202 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200203 } catch (JsonParseException e) {
204 log.error("Error in JSON file", e);
205 System.exit(1);
206 } catch (JsonMappingException e) {
207 log.error("Error in JSON file", e);
208 System.exit(1);
209 } catch (IOException e) {
210 log.error("Error reading JSON file", e);
211 System.exit(1);
212 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200213
214 //Populate the interface Patricia Trie
215 for (Interface intf : interfaces.values()) {
216 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
217 interfacePtrie.put(prefix, intf);
218 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700219 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800220
221 @Override
222 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700223 Collection<Class<? extends IFloodlightService>> l
224 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800225 l.add(IBgpRouteService.class);
226 return l;
227 }
228
229 @Override
230 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700231 Map<Class<? extends IFloodlightService>, IFloodlightService> m
232 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800233 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800234 return m;
235 }
236
pingping-lina2cbfad2013-03-07 08:39:21 +0800237 @Override
238 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700239 Collection<Class<? extends IFloodlightService>> l
240 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800241 l.add(IFloodlightProviderService.class);
242 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700243 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800244 return l;
245 }
246
247 @Override
248 public void init(FloodlightModuleContext context)
249 throws FloodlightModuleException {
250
Jonathan Hart29b972d2013-08-12 23:43:51 +1200251 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200252 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200253
254 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200255
pingping-lina2cbfad2013-03-07 08:39:21 +0800256 // Register floodlight provider and REST handler.
257 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800258 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200259 restApi = context.getServiceImpl(IRestApiService.class);
260
261 //TODO We'll initialise this here for now, but it should really be done as
262 //part of the controller core
Jonathan Hart2f790d22013-08-15 14:01:24 +1200263 proxyArp = new ProxyArpManager(floodlightProvider, topology);
pingping-lina2cbfad2013-03-07 08:39:21 +0800264
Jonathan Hart98957bf2013-07-01 14:49:24 +1200265 linkUpdates = new ArrayList<LDUpdate>();
266 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
267 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700268
269 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200270
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200271 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200272 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
273 HashMultimap.<InetAddress, RibUpdate>create());
274
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200275 pushedPaths = new HashMap<InetAddress, Path>();
276 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200277 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
278
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200279 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
280 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
281
Jonathan Hart61ba9372013-05-19 20:10:29 -0700282 //Read in config values
283 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
284 if (bgpdRestIp == null){
285 log.error("BgpdRestIp property not found in config file");
286 System.exit(1);
287 }
288 else {
289 log.info("BgpdRestIp set to {}", bgpdRestIp);
290 }
291
292 routerId = context.getConfigParams(this).get("RouterId");
293 if (routerId == null){
294 log.error("RouterId property not found in config file");
295 System.exit(1);
296 }
297 else {
298 log.info("RouterId set to {}", routerId);
299 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200300
Jonathan Hart9575cb62013-07-05 13:43:49 +1200301 String configFilenameParameter = context.getConfigParams(this).get("configfile");
302 if (configFilenameParameter != null){
303 configFilename = configFilenameParameter;
304 }
305 log.debug("Config file set to {}", configFilename);
306
307 readGatewaysConfiguration(configFilename);
Jonathan Hart2f790d22013-08-15 14:01:24 +1200308
Jonathan Hart1633a402013-08-24 11:38:56 +1200309 proxyArp.setL3Mode(interfacePtrie, interfaces.values(), bgpdMacAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200310 }
311
312 @Override
313 public void startUp(FloodlightModuleContext context) {
314 restApi.addRestletRoutable(new BgpRouteWebRoutable());
315 topology.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200316 floodlightProvider.addOFSwitchListener(this);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200317
Jonathan Hart2f790d22013-08-15 14:01:24 +1200318 proxyArp.startUp();
319
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200320 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
321
322 //Retrieve the RIB from BGPd during startup
323 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800324 }
325
Jonathan Hart29b972d2013-08-12 23:43:51 +1200326 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800327 return ptree;
328 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700329
330 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200331 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800332 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700333
pingping-line2a09ca2013-03-23 09:33:58 +0800334 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700335 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800336 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700337
pingping-line2a09ca2013-03-23 09:33:58 +0800338 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700339 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800340 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800341
Jonathan Hart61ba9372013-05-19 20:10:29 -0700342 private void retrieveRib(){
343 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
344 String response = RestClient.get(url);
345
346 if (response.equals("")){
347 return;
348 }
349
350 response = response.replaceAll("\"", "'");
351 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
352 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
353 String router_id = jsonObj.getString("router-id");
354
355 int size = rib_json_array.size();
356
357 log.info("Retrived RIB of {} entries from BGPd", size);
358
359 for (int j = 0; j < size; j++) {
360 JSONObject second_json_object = rib_json_array.getJSONObject(j);
361 String prefix = second_json_object.getString("prefix");
362 String nexthop = second_json_object.getString("nexthop");
363
364 //insert each rib entry into the local rib;
365 String[] substring = prefix.split("/");
366 String prefix1 = substring[0];
367 String mask1 = substring[1];
368
369 Prefix p;
370 try {
371 p = new Prefix(prefix1, Integer.valueOf(mask1));
372 } catch (NumberFormatException e) {
373 log.warn("Wrong mask format in RIB JSON: {}", mask1);
374 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200375 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700376 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
377 continue;
378 }
379
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200380 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200381
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200382 try {
383 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
384 } catch (InterruptedException e) {
385 log.debug("Interrupted while pushing onto update queue");
386 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700387 }
388 }
389
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200390 @Override
391 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200392 try {
393 ribUpdates.put(update);
394 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200395 log.debug("Interrupted while putting on ribUpdates queue", e);
396 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200397 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200398 }
399
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200400 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200401 Prefix prefix = update.getPrefix();
402
Jonathan Hart9ea31212013-08-12 21:40:34 +1200403 log.debug("Processing prefix add {}", prefix);
404
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200405 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200406
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200407 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200408 //There was an existing nexthop for this prefix. This update supersedes that,
409 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200410 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200411 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200412
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200413 if (update.getRibEntry().getNextHop().equals(
414 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200415 //Route originated by SDN domain
416 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200417 log.debug("Own route {} to {}", prefix,
418 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200419 return;
420 }
421
422 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200423 }
424
Jonathan Hart309889c2013-08-13 23:26:24 +1200425 private void _processRibAdd(RibUpdate update) {
426 Prefix prefix = update.getPrefix();
427 RibEntry rib = update.getRibEntry();
428
429 InetAddress dstIpAddress = rib.getNextHop();
430
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200431 //See if we know the MAC address of the next hop
Jonathan Hart309889c2013-08-13 23:26:24 +1200432 byte[] nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200433
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200434 //Find the attachment point (egress interface) of the next hop
435 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200436 if (bgpPeers.containsKey(dstIpAddress)) {
437 //Route to a peer
438 log.debug("Route to peer {}", dstIpAddress);
439 BgpPeer peer = bgpPeers.get(dstIpAddress);
440 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200441 }
442 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200443 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200444 log.debug("Route to non-peer {}", dstIpAddress);
445 egressInterface = interfacePtrie.match(
446 new Prefix(dstIpAddress.getAddress(), 32));
447 if (egressInterface == null) {
448 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
449 return;
450 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200451 }
452
453 if (nextHopMacAddress == null) {
454 prefixesWaitingOnArp.put(dstIpAddress,
455 new RibUpdate(Operation.UPDATE, prefix, rib));
456 proxyArp.sendArpRequest(dstIpAddress, this, true);
457 return;
458 }
459 else {
460 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200461 //If the prefix is for a non-peer we need to ensure there's a path,
462 //and push one if there isn't.
463 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200464 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200465 path = new Path(egressInterface, dstIpAddress);
466 setUpDataPath(path, MACAddress.valueOf(nextHopMacAddress));
Jonathan Hart309889c2013-08-13 23:26:24 +1200467 pushedPaths.put(dstIpAddress, path);
468 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200469
470 path.incrementUsers();
471 prefixToPath.put(prefix, path);
472 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200473
474 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200475 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
476 }
477 }
478
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200479 private void addPrefixFlows(Prefix prefix, Interface egressInterface, byte[] nextHopMacAddress) {
480 log.debug("Adding flows for prefix {} added, next hop mac {}",
481 prefix, HexString.toHexString(nextHopMacAddress));
482
483 //Add a flow to rewrite mac for this prefix to all other border switches
484 for (Interface srcInterface : interfaces.values()) {
485 if (srcInterface == egressInterface) {
486 //Don't push a flow for the switch where this peer is attached
487 continue;
488 }
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200489
490
491 DataPath shortestPath;
492 if (topoRouteTopology == null) {
493 shortestPath = topoRouteService.getShortestPath(
494 srcInterface.getSwitchPort(),
495 egressInterface.getSwitchPort());
496 }
497 else {
498 shortestPath = topoRouteService.getTopoShortestPath(
499 topoRouteTopology, srcInterface.getSwitchPort(),
500 egressInterface.getSwitchPort());
501 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200502
503 if (shortestPath == null){
504 log.debug("Shortest path between {} and {} not found",
505 srcInterface.getSwitchPort(),
506 egressInterface.getSwitchPort());
507 return; // just quit here?
508 }
509
510 //Set up the flow mod
511 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
512 .getMessage(OFType.FLOW_MOD);
513
514 fm.setIdleTimeout((short)0)
515 .setHardTimeout((short)0)
516 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
517 .setCookie(MAC_RW_COOKIE)
518 .setCommand(OFFlowMod.OFPFC_ADD)
519 .setPriority(SDNIP_PRIORITY)
520 .setLengthU(OFFlowMod.MINIMUM_LENGTH
521 + OFActionDataLayerDestination.MINIMUM_LENGTH
522 + OFActionOutput.MINIMUM_LENGTH);
523
524 OFMatch match = new OFMatch();
525 match.setDataLayerType(Ethernet.TYPE_IPv4);
526 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
527
528 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
529 fm.setMatch(match);
530
531 //Set up MAC rewrite action
532 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
533 macRewriteAction.setDataLayerAddress(nextHopMacAddress);
534
535 //Set up output action
536 OFActionOutput outputAction = new OFActionOutput();
537 outputAction.setMaxLength((short)0xffff);
538 Port outputPort = shortestPath.flowEntries().get(0).outPort();
539 outputAction.setPort(outputPort.value());
540
541 List<OFAction> actions = new ArrayList<OFAction>();
542 actions.add(macRewriteAction);
543 actions.add(outputAction);
544 fm.setActions(actions);
545
546 //Write to switch
547 IOFSwitch sw = floodlightProvider.getSwitches()
548 .get(srcInterface.getDpid());
549
550 if (sw == null){
551 log.warn("Switch not found when pushing flow mod");
552 continue;
553 }
554
555 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
556
557 List<OFMessage> msglist = new ArrayList<OFMessage>();
558 msglist.add(fm);
559 try {
560 sw.write(msglist, null);
561 sw.flush();
562 } catch (IOException e) {
563 log.error("Failure writing flow mod", e);
564 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200565 }
566 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200567
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200568 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200569 Prefix prefix = update.getPrefix();
570
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200571 if (ptree.remove(prefix, update.getRibEntry())) {
572 /*
573 * Only delete flows if an entry was actually removed from the trie.
574 * If no entry was removed, the <prefix, nexthop> wasn't there so
575 * it's probably already been removed and we don't need to do anything
576 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200577 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200578 }
579 }
580
581 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
582 deletePrefixFlows(prefix);
583
584 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
585 log.debug("is peer {}", bgpPeers.containsKey(ribEntry.getNextHop()));
586 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
587 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200588 //Path path = prefixToPath.get(prefix);
589 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200590
591 if (path == null) {
592 log.error("No path found for non-peer path");
593 }
594
595 path.decrementUsers();
596 log.debug("users {}, permanent {}", path.getUsers(), path.isPermanent());
597 if (path.getUsers() <= 0 && !path.isPermanent()) {
598 deletePath(path);
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200599 pushedPaths.remove(path.getDstIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200600 }
601 }
602 }
603
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200604 private void deletePrefixFlows(Prefix prefix) {
605 Collection<PushedFlowMod> pushedFlowMods
606 = pushedFlows.removeAll(prefix);
607
608 for (PushedFlowMod pfm : pushedFlowMods) {
609 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
610 new Object[] {HexString.toHexString(pfm.getDpid()),
611 pfm.getFlowMod().getMatch().getNetworkDestination() +
612 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
613 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
614 .getDataLayerAddress())});
615
616 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
617 }
618 }
619
620 private void deletePath(Path path) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200621 for (PushedFlowMod pfm : path.getFlowMods()) {
622 log.debug("Pushing a DELETE flow mod to {}, dst MAC {}",
623 new Object[] {HexString.toHexString(pfm.getDpid()),
624 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
625 });
626
627 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
628 }
629 }
630
631 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
632 addFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
633 .setOutPort(OFPort.OFPP_NONE)
634 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
635
636 addFlowMod.getActions().clear();
637
638 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
639 if (sw == null) {
640 log.warn("Switch not found when pushing delete flow mod");
641 return;
642 }
643
644 try {
645 sw.write(addFlowMod, null);
646 sw.flush();
647 } catch (IOException e) {
648 log.error("Failure writing flow mod", e);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200649 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200650 }
651
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200652 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200653 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200654
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700655 /*
656 * On startup we need to calculate a full mesh of paths between all gateway
657 * switches
658 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200659 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700660 //For each border router, calculate and install a path from every other
661 //border switch to said border router. However, don't install the entry
662 //in to the first hop switch, as we need to install an entry to rewrite
663 //for each prefix received. This will be done later when prefixes have
664 //actually been received.
665
Jonathan Hartc824ad02013-07-03 15:58:45 +1200666 for (BgpPeer peer : bgpPeers.values()) {
667 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200668
Jonathan Hart309889c2013-08-13 23:26:24 +1200669 //We know there's not already a Path here pushed, because this is
670 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200671 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200672 path.setPermanent();
673
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200674 //See if we know the MAC address of the peer. If not we can't
675 //do anything until we learn it
676 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
677 if (mac == null) {
678 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
679 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200680 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700681
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200682 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
683 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700684 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200685
686 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200687 setUpDataPath(path, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700688 }
689 }
690
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200691 private void setUpDataPath(Path path, MACAddress dstMacAddress) {
692 calculateAndPushPath(path, dstMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200693 }
694
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200695 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200696 Interface dstInterface = path.getDstInterface();
697
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200698 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
699 dstMacAddress);
700
Jonathan Hart309889c2013-08-13 23:26:24 +1200701 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
702
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200703 for (Interface srcInterface : interfaces.values()) {
704 if (dstInterface.equals(srcInterface.getName())){
705 continue;
706 }
707
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200708 DataPath shortestPath;
709 if (topoRouteTopology == null) {
710 log.debug("Using database topo");
711 shortestPath = topoRouteService.getShortestPath(
712 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
713 }
714 else {
715 log.debug("Using prepared topo");
716 shortestPath = topoRouteService.getTopoShortestPath(topoRouteTopology,
717 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
718 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200719
720 if (shortestPath == null){
721 log.debug("Shortest path between {} and {} not found",
722 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
723 return; // just quit here?
724 }
725
Jonathan Hart309889c2013-08-13 23:26:24 +1200726 pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200727 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200728
729 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200730 }
731
Jonathan Hart309889c2013-08-13 23:26:24 +1200732 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
733 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
734
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700735 //Set up the flow mod
736 OFFlowMod fm =
737 (OFFlowMod) floodlightProvider.getOFMessageFactory()
738 .getMessage(OFType.FLOW_MOD);
739
740 OFActionOutput action = new OFActionOutput();
741 action.setMaxLength((short)0xffff);
742 List<OFAction> actions = new ArrayList<OFAction>();
743 actions.add(action);
744
745 fm.setIdleTimeout((short)0)
746 .setHardTimeout((short)0)
747 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
748 .setCookie(L2_FWD_COOKIE)
749 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700750 .setActions(actions)
751 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
752
753 //Don't push the first flow entry. We need to push entries in the
754 //first switch based on IP prefix which we don't know yet.
755 for (int i = 1; i < flowEntries.size(); i++){
756 FlowEntry flowEntry = flowEntries.get(i);
757
758 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200759 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700760 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
761 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
762
763 fm.setMatch(match);
764
765 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
766
767 if (sw == null){
768 log.warn("Switch not found when pushing flow mod");
769 continue;
770 }
771
Jonathan Hart309889c2013-08-13 23:26:24 +1200772 flowMods.add(new PushedFlowMod(sw.getId(), fm));
773
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700774 List<OFMessage> msglist = new ArrayList<OFMessage>();
775 msglist.add(fm);
776 try {
777 sw.write(msglist, null);
778 sw.flush();
779 } catch (IOException e) {
780 log.error("Failure writing flow mod", e);
781 }
782
783 try {
784 fm = fm.clone();
785 } catch (CloneNotSupportedException e1) {
786 log.error("Failure cloning flow mod", e1);
787 }
788 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200789
790 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700791 }
792
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200793 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200794 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200795 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
796
797 DataPath path = topoRouteService.getShortestPath(
798 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
799
800 if (path == null){
801 log.debug("Unable to compute path for BGP traffic for {}",
802 bgpPeer.getIpAddress());
803 continue;
804 }
805
806 //Set up the flow mod
807 OFFlowMod fm =
808 (OFFlowMod) floodlightProvider.getOFMessageFactory()
809 .getMessage(OFType.FLOW_MOD);
810
811 OFActionOutput action = new OFActionOutput();
812 action.setMaxLength((short)0xffff);
813 List<OFAction> actions = new ArrayList<OFAction>();
814 actions.add(action);
815
816 fm.setIdleTimeout((short)0)
817 .setHardTimeout((short)0)
818 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
819 .setCookie(BGP_COOKIE)
820 .setCommand(OFFlowMod.OFPFC_ADD)
821 .setPriority(SDNIP_PRIORITY)
822 .setActions(actions)
823 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
824
825 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
826 OFMatch forwardMatchSrc = new OFMatch();
827
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200828 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
829 + "/32";
830 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
831 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200832
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200833 //Common match fields
834 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200835 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
836 forwardMatchSrc.setTransportDestination(BGP_PORT);
837 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
838 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
839
840
841 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
842
843 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
844 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
845
846 OFMatch forwardMatchDst = forwardMatchSrc.clone();
847
848 forwardMatchSrc.setTransportSource(BGP_PORT);
849 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
850 forwardMatchDst.setTransportDestination(BGP_PORT);
851 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
852
853 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
854 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
855
856 OFMatch reverseMatchDst = reverseMatchSrc.clone();
857
858 reverseMatchSrc.setTransportSource(BGP_PORT);
859 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
860 reverseMatchDst.setTransportDestination(BGP_PORT);
861 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
862
863 fm.setMatch(forwardMatchSrc);
864
Jonathan Hart38c84932013-08-10 17:49:27 +1200865 OFMatch forwardIcmpMatch = new OFMatch();
866 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
867 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
868 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
869 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
870
871 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
872 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
873 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
874
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200875 for (FlowEntry flowEntry : path.flowEntries()){
876 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
877 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200878 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200879 try {
880 forwardFlowModSrc = fm.clone();
881 forwardFlowModDst = fm.clone();
882 reverseFlowModSrc = fm.clone();
883 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200884 forwardIcmp = fm.clone();
885 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200886 } catch (CloneNotSupportedException e) {
887 log.warn("Clone failed", e);
888 continue;
889 }
890
891 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
892 forwardFlowModSrc.setMatch(forwardMatchSrc);
893 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
894 .setPort(flowEntry.outPort().value());
895
896 forwardMatchDst.setInputPort(flowEntry.inPort().value());
897 forwardFlowModDst.setMatch(forwardMatchDst);
898 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
899 .setPort(flowEntry.outPort().value());
900
901 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
902 reverseFlowModSrc.setMatch(reverseMatchSrc);
903 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
904 .setPort(flowEntry.inPort().value());
905
906 reverseMatchDst.setInputPort(flowEntry.outPort().value());
907 reverseFlowModDst.setMatch(reverseMatchDst);
908 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
909 .setPort(flowEntry.inPort().value());
910
Jonathan Hart38c84932013-08-10 17:49:27 +1200911 ((OFActionOutput)forwardIcmp.getActions().get(0))
912 .setPort(flowEntry.outPort().value());
913 forwardIcmp.setMatch(forwardIcmpMatch);
914
915 ((OFActionOutput)reverseIcmp.getActions().get(0))
916 .setPort(flowEntry.inPort().value());
917 reverseIcmp.setMatch(reverseIcmpMatch);
918
919
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200920 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
921
Jonathan Hart38c84932013-08-10 17:49:27 +1200922 if (sw == null) {
923 log.warn("Switch not found when pushing BGP paths");
924 return;
925 }
926
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200927 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
928 msgList.add(forwardFlowModSrc);
929 msgList.add(forwardFlowModDst);
930 msgList.add(reverseFlowModSrc);
931 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +1200932 msgList.add(forwardIcmp);
933 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200934
935 try {
936 sw.write(msgList, null);
937 sw.flush();
938 } catch (IOException e) {
939 log.error("Failure writing flow mod", e);
940 }
941 }
942 }
943 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200944
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200945 @Override
946 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
947 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
948 MACAddress.valueOf(macAddress).toString());
949
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200950 /*
951 * We synchronize on this to prevent changes to the ptree while we're pushing
952 * flows to the switches. If the ptree changes, the ptree and switches
953 * could get out of sync.
954 */
955 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200956 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200957
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200958 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200959 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200960 path.getDstIpAddress().getHostAddress(),
Jonathan Hart309889c2013-08-13 23:26:24 +1200961 MACAddress.valueOf(macAddress),
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200962 path.getDstInterface().getSwitchPort()});
963 //These paths should always be to BGP peers. Paths to non-peers are
964 //handled once the first prefix is ready to push
965 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200966 //A path already got pushed to this endpoint while we were waiting
967 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200968 if (path.isPermanent()) {
969 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200970 }
971 }
972 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200973 setUpDataPath(path, MACAddress.valueOf(macAddress));
974 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200975 }
976 }
977
Jonathan Hart309889c2013-08-13 23:26:24 +1200978 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
979
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200980 for (RibUpdate update : prefixesToPush) {
981 //These will always be adds
982
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200983 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200984 if (rib != null && rib.equals(update.getRibEntry())) {
985 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200986 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200987 //We only push prefix flows if the prefix is still in the ptree
988 //and the next hop is the same as our update. The prefix could
989 //have been removed while we were waiting for the ARP, or the
990 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200991 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200992 } else {
993 log.debug("Received ARP response, but {},{} is no longer in ptree",
994 update.getPrefix(), update.getRibEntry());
995 }
996 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200997 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200998 }
999
Jonathan Hartc82051c2013-08-24 15:12:20 +12001000 private void setupArpFlows() {
1001 OFMatch match = new OFMatch();
1002 match.setDataLayerType(Ethernet.TYPE_ARP);
1003 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1004
1005 OFFlowMod fm = new OFFlowMod();
1006 fm.setMatch(match);
1007
1008 OFActionOutput action = new OFActionOutput();
1009 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1010 action.setMaxLength((short)0xffff);
1011 List<OFAction> actions = new ArrayList<OFAction>(1);
1012 actions.add(action);
1013 fm.setActions(actions);
1014
1015 fm.setIdleTimeout((short)0)
1016 .setHardTimeout((short)0)
1017 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1018 .setCookie(0)
1019 .setCommand(OFFlowMod.OFPFC_ADD)
1020 .setPriority(ARP_PRIORITY)
1021 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1022
1023 for (String strdpid : switches){
1024 IOFSwitch sw = floodlightProvider.getSwitches().get(HexString.toLong(strdpid));
1025 if (sw == null) {
1026 log.debug("Couldn't find switch to push ARP flow");
1027 }
1028 else {
1029 try {
1030 sw.write(fm, null);
1031 } catch (IOException e) {
1032 log.warn("Failure writing ARP flow to switch", e);
1033 }
1034 }
1035 }
1036 }
1037
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001038 private void beginRouting(){
1039 log.debug("Topology is now ready, beginning routing function");
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001040 topoRouteTopology = topoRouteService.prepareShortestPathTopo();
1041
Jonathan Hartc82051c2013-08-24 15:12:20 +12001042 setupArpFlows();
1043
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001044 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001045 setupFullMesh();
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001046
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001047 bgpUpdatesExecutor.execute(new Runnable() {
1048 @Override
1049 public void run() {
1050 doUpdatesThread();
1051 }
1052 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001053 }
1054
1055 private void checkSwitchesConnected(){
1056 for (String dpid : switches){
1057 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1058 log.debug("Not all switches are here yet");
1059 return;
1060 }
1061 }
1062 switchesConnected = true;
1063 }
1064
Jonathan Hartc824ad02013-07-03 15:58:45 +12001065 //Actually we only need to go half way round to verify full mesh connectivity
1066 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001067 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001068 for (Interface dstInterface : interfaces.values()) {
1069 for (Interface srcInterface : interfaces.values()) {
1070 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001071 continue;
1072 }
1073
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001074 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001075 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001076
1077 if (shortestPath == null){
1078 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001079 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001080 return;
1081 }
1082 }
1083 }
1084 topologyReady = true;
1085 }
1086
1087 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001088 if (!switchesConnected){
1089 checkSwitchesConnected();
1090 }
1091 boolean oldTopologyReadyStatus = topologyReady;
1092 if (switchesConnected && !topologyReady){
1093 checkTopologyReady();
1094 }
1095 if (!oldTopologyReadyStatus && topologyReady){
1096 beginRouting();
1097 }
1098 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001099
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001100 private void doUpdatesThread() {
1101 boolean interrupted = false;
1102 try {
1103 while (true) {
1104 try {
1105 RibUpdate update = ribUpdates.take();
1106 switch (update.getOperation()){
1107 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001108 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001109 break;
1110 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001111 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001112 break;
1113 }
1114 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001115 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001116 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001117 } catch (Exception e) {
1118 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001119 }
1120 }
1121 } finally {
1122 if (interrupted) {
1123 Thread.currentThread().interrupt();
1124 }
1125 }
1126 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001127
1128 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001129 public void topologyChanged() {
1130 if (topologyReady) {
1131 return;
1132 }
1133
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001134 boolean refreshNeeded = false;
1135 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1136 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1137 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001138 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001139 refreshNeeded = true;
1140 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001141
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001142 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001143
Jonathan Hart98957bf2013-07-01 14:49:24 +12001144 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1145 synchronized (linkUpdates) {
1146 linkUpdates.add(ldu);
1147 }
1148 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001149 }
1150
Jonathan Hart64c0b202013-08-20 15:45:07 +12001151 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001152 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001153 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001154 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001155
1156 @Override
1157 public void addedSwitch(IOFSwitch sw) {
1158 if (!topologyReady) {
1159 sw.clearAllFlowMods();
1160 }
1161 }
1162
1163 @Override
1164 public void removedSwitch(IOFSwitch sw) {
1165 // TODO Auto-generated method stub
1166
1167 }
1168
1169 @Override
1170 public void switchPortChanged(Long switchId) {
1171 // TODO Auto-generated method stub
1172
1173 }
1174
1175 @Override
1176 public String getName() {
1177 // TODO Auto-generated method stub
1178 return null;
1179 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001180}