blob: 52c4bfdaca3f491be117eab6ac60aaf49af4577e [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 Harte7694532013-09-12 12:34:46 +120041import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120042import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
Jonathan Hart5afde492013-10-01 12:30:53 +130043import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120044import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070045import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070046import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120047import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070048import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070049import net.onrc.onos.ofcontroller.util.Port;
50import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080051import net.sf.json.JSONArray;
52import net.sf.json.JSONObject;
53import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080054
Jonathan Hartd1f23252013-06-13 15:17:05 +120055import org.codehaus.jackson.JsonParseException;
56import org.codehaus.jackson.map.JsonMappingException;
57import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070058import org.openflow.protocol.OFFlowMod;
59import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070060import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120061import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070062import org.openflow.protocol.OFType;
63import org.openflow.protocol.action.OFAction;
64import org.openflow.protocol.action.OFActionDataLayerDestination;
65import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120066import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080067import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
69
Jonathan Hart4dfc3652013-08-02 20:22:36 +120070import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120071import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120072import com.google.common.collect.Multimaps;
73import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120074import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120075import com.google.common.util.concurrent.ThreadFactoryBuilder;
76
Jonathan Hart1236a9b2013-06-18 22:10:05 +120077public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120078 ITopologyListener, IArpRequester,
Jonathan Hart5afde492013-10-01 12:30:53 +130079 IOFSwitchListener, ILayer3InfoService,
80 IProxyArpService {
pingping-lina2cbfad2013-03-07 08:39:21 +080081
82 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
83
84 protected IFloodlightProviderService floodlightProvider;
85 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070086 protected ITopoRouteService topoRouteService;
Jonathan Harte7694532013-09-12 12:34:46 +120087 protected ILinkDiscoveryService linkDiscoveryService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070088 protected IRestApiService restApi;
89
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120090 protected ProxyArpManager proxyArp;
91
Jonathan Hart29b972d2013-08-12 23:43:51 +120092 protected IPatriciaTrie<RibEntry> ptree;
Jonathan Hartabf10222013-08-13 10:19:34 +120093 protected IPatriciaTrie<Interface> interfacePtrie;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120094 protected BlockingQueue<RibUpdate> ribUpdates;
95
Jonathan Hart61ba9372013-05-19 20:10:29 -070096 protected String bgpdRestIp;
97 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120098 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070099
100 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
101 //the controller/OS should hand out cookie IDs to prevent conflicts.
102 protected final long APP_COOKIE = 0xa0000000000000L;
103 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
104 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
105 //Cookie for flows in ingress switches that rewrite the MAC address
106 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200107 //Cookie for flows that setup BGP paths
108 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200109 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
110 //need to be higher priority than this otherwise the rewrite may not get done
111 protected final short SDNIP_PRIORITY = 10;
Jonathan Hartc82051c2013-08-24 15:12:20 +1200112 protected final short ARP_PRIORITY = 20;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700113
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200114 protected final short BGP_PORT = 179;
115
Jonathan Hart98957bf2013-07-01 14:49:24 +1200116 protected final int TOPO_DETECTION_WAIT = 2; //seconds
117
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200118 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200119 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200120 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200121 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200122 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart2f790d22013-08-15 14:01:24 +1200123 protected MACAddress bgpdMacAddress;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200124
125 //True when all switches have connected
126 protected volatile boolean switchesConnected = false;
127 //True when we have a full mesh of shortest paths between gateways
128 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200129
Jonathan Hart98957bf2013-07-01 14:49:24 +1200130 protected ArrayList<LDUpdate> linkUpdates;
131 protected SingletonTask topologyChangeDetectorTask;
132
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200133 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200134
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200135 protected Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200136
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200137 protected ExecutorService bgpUpdatesExecutor;
138
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200139 protected Map<InetAddress, Path> pushedPaths;
140 protected Map<Prefix, Path> prefixToPath;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200141 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200142
Jonathan Hart1912afc2013-10-11 12:02:44 +1300143 private FlowCache flowCache;
144
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200145 protected volatile Map<Long, ?> topoRouteTopology = null;
Jonathan Harte4c98692013-10-18 17:40:03 -0700146
Jonathan Hart98957bf2013-07-01 14:49:24 +1200147 protected class TopologyChangeDetector implements Runnable {
148 @Override
149 public void run() {
150 log.debug("Running topology change detection task");
151 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200152 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200153 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
154
155 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200156
157 Iterator<LDUpdate> it = linkUpdates.iterator();
158 while (it.hasNext()){
159 LDUpdate ldu = it.next();
160 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
161 ldu.getDst(), ldu.getDstPort());
162
163 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200164 it.remove();
165 }
166 }
167 }
168
Jonathan Hart64c0b202013-08-20 15:45:07 +1200169 if (!topologyReady) {
170 if (linkUpdates.isEmpty()){
171 //All updates have been seen in network map.
172 //We can check if topology is ready
173 log.debug("No known changes outstanding. Checking topology now");
174 checkStatus();
175 }
176 else {
177 //We know of some link updates that haven't propagated to the database yet
178 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
179 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
180 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200181 }
182 }
183 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700184
Jonathan Hartd1f23252013-06-13 15:17:05 +1200185 private void readGatewaysConfiguration(String gatewaysFilename){
186 File gatewaysFile = new File(gatewaysFilename);
187 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700188
Jonathan Hartd1f23252013-06-13 15:17:05 +1200189 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200190 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
191
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200192 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200193 interfaces = new HashMap<String, Interface>();
194 for (Interface intf : config.getInterfaces()){
195 interfaces.put(intf.getName(), intf);
196 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200197 bgpPeers = new HashMap<InetAddress, BgpPeer>();
198 for (BgpPeer peer : config.getPeers()){
199 bgpPeers.put(peer.getIpAddress(), peer);
200 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200201
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200202 bgpdAttachmentPoint = new SwitchPort(
203 new Dpid(config.getBgpdAttachmentDpid()),
204 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200205
Jonathan Hart2f790d22013-08-15 14:01:24 +1200206 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200207 } catch (JsonParseException e) {
208 log.error("Error in JSON file", e);
209 System.exit(1);
210 } catch (JsonMappingException e) {
211 log.error("Error in JSON file", e);
212 System.exit(1);
213 } catch (IOException e) {
214 log.error("Error reading JSON file", e);
215 System.exit(1);
216 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200217
218 //Populate the interface Patricia Trie
219 for (Interface intf : interfaces.values()) {
220 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
221 interfacePtrie.put(prefix, intf);
222 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700223 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800224
225 @Override
226 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700227 Collection<Class<? extends IFloodlightService>> l
228 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800229 l.add(IBgpRouteService.class);
230 return l;
231 }
232
233 @Override
234 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700235 Map<Class<? extends IFloodlightService>, IFloodlightService> m
236 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800237 m.put(IBgpRouteService.class, this);
Jonathan Hart5afde492013-10-01 12:30:53 +1300238 m.put(IProxyArpService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800239 return m;
240 }
241
pingping-lina2cbfad2013-03-07 08:39:21 +0800242 @Override
243 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700244 Collection<Class<? extends IFloodlightService>> l
245 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800246 l.add(IFloodlightProviderService.class);
247 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700248 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800249 return l;
250 }
251
252 @Override
253 public void init(FloodlightModuleContext context)
254 throws FloodlightModuleException {
255
Jonathan Hart29b972d2013-08-12 23:43:51 +1200256 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200257 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200258
259 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200260
pingping-lina2cbfad2013-03-07 08:39:21 +0800261 // Register floodlight provider and REST handler.
262 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800263 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200264 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200265 restApi = context.getServiceImpl(IRestApiService.class);
266
267 //TODO We'll initialise this here for now, but it should really be done as
268 //part of the controller core
Jonathan Hart5afde492013-10-01 12:30:53 +1300269 proxyArp = new ProxyArpManager(floodlightProvider, topology, this, restApi);
pingping-lina2cbfad2013-03-07 08:39:21 +0800270
Jonathan Hart98957bf2013-07-01 14:49:24 +1200271 linkUpdates = new ArrayList<LDUpdate>();
272 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
273 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700274
275 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200276
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200277 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200278 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
279 HashMultimap.<InetAddress, RibUpdate>create());
280
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200281 pushedPaths = new HashMap<InetAddress, Path>();
282 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200283 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
284
Jonathan Hart1912afc2013-10-11 12:02:44 +1300285 flowCache = new FlowCache(floodlightProvider);
286
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200287 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
288 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
289
Jonathan Hart61ba9372013-05-19 20:10:29 -0700290 //Read in config values
291 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
292 if (bgpdRestIp == null){
293 log.error("BgpdRestIp property not found in config file");
294 System.exit(1);
295 }
296 else {
297 log.info("BgpdRestIp set to {}", bgpdRestIp);
298 }
299
300 routerId = context.getConfigParams(this).get("RouterId");
301 if (routerId == null){
302 log.error("RouterId property not found in config file");
303 System.exit(1);
304 }
305 else {
306 log.info("RouterId set to {}", routerId);
307 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200308
Jonathan Hart9575cb62013-07-05 13:43:49 +1200309 String configFilenameParameter = context.getConfigParams(this).get("configfile");
310 if (configFilenameParameter != null){
311 configFilename = configFilenameParameter;
312 }
313 log.debug("Config file set to {}", configFilename);
314
315 readGatewaysConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200316 }
317
318 @Override
319 public void startUp(FloodlightModuleContext context) {
320 restApi.addRestletRoutable(new BgpRouteWebRoutable());
321 topology.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200322 floodlightProvider.addOFSwitchListener(this);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200323
Jonathan Hart2f790d22013-08-15 14:01:24 +1200324 proxyArp.startUp();
325
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200326 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
327
328 //Retrieve the RIB from BGPd during startup
329 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800330 }
331
Jonathan Hart29b972d2013-08-12 23:43:51 +1200332 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800333 return ptree;
334 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700335
336 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200337 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800338 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700339
pingping-line2a09ca2013-03-23 09:33:58 +0800340 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700341 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800342 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700343
pingping-line2a09ca2013-03-23 09:33:58 +0800344 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700345 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800346 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800347
Jonathan Hart61ba9372013-05-19 20:10:29 -0700348 private void retrieveRib(){
349 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
350 String response = RestClient.get(url);
351
352 if (response.equals("")){
353 return;
354 }
355
356 response = response.replaceAll("\"", "'");
357 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
358 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
359 String router_id = jsonObj.getString("router-id");
360
361 int size = rib_json_array.size();
362
363 log.info("Retrived RIB of {} entries from BGPd", size);
364
365 for (int j = 0; j < size; j++) {
366 JSONObject second_json_object = rib_json_array.getJSONObject(j);
367 String prefix = second_json_object.getString("prefix");
368 String nexthop = second_json_object.getString("nexthop");
369
370 //insert each rib entry into the local rib;
371 String[] substring = prefix.split("/");
372 String prefix1 = substring[0];
373 String mask1 = substring[1];
374
375 Prefix p;
376 try {
377 p = new Prefix(prefix1, Integer.valueOf(mask1));
378 } catch (NumberFormatException e) {
379 log.warn("Wrong mask format in RIB JSON: {}", mask1);
380 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200381 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700382 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
383 continue;
384 }
385
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200386 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200387
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200388 try {
389 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
390 } catch (InterruptedException e) {
391 log.debug("Interrupted while pushing onto update queue");
392 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700393 }
394 }
395
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200396 @Override
397 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200398 try {
399 ribUpdates.put(update);
400 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200401 log.debug("Interrupted while putting on ribUpdates queue", e);
402 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200403 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200404 }
405
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200406 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200407 Prefix prefix = update.getPrefix();
408
Jonathan Hart9ea31212013-08-12 21:40:34 +1200409 log.debug("Processing prefix add {}", prefix);
410
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200411 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200412
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200413 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200414 //There was an existing nexthop for this prefix. This update supersedes that,
415 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200416 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200417 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200418
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200419 if (update.getRibEntry().getNextHop().equals(
420 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200421 //Route originated by SDN domain
422 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200423 log.debug("Own route {} to {}", prefix,
424 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200425 return;
426 }
427
428 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200429 }
430
Jonathan Hart309889c2013-08-13 23:26:24 +1200431 private void _processRibAdd(RibUpdate update) {
432 Prefix prefix = update.getPrefix();
433 RibEntry rib = update.getRibEntry();
434
435 InetAddress dstIpAddress = rib.getNextHop();
436
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200437 //See if we know the MAC address of the next hop
Jonathan Hartabad6a52013-09-30 18:17:21 +1300438 MACAddress nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200439
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200440 //Find the attachment point (egress interface) of the next hop
441 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200442 if (bgpPeers.containsKey(dstIpAddress)) {
443 //Route to a peer
444 log.debug("Route to peer {}", dstIpAddress);
445 BgpPeer peer = bgpPeers.get(dstIpAddress);
446 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200447 }
448 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200449 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200450 log.debug("Route to non-peer {}", dstIpAddress);
451 egressInterface = interfacePtrie.match(
452 new Prefix(dstIpAddress.getAddress(), 32));
453 if (egressInterface == null) {
454 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
455 return;
456 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200457 }
458
459 if (nextHopMacAddress == null) {
460 prefixesWaitingOnArp.put(dstIpAddress,
461 new RibUpdate(Operation.UPDATE, prefix, rib));
462 proxyArp.sendArpRequest(dstIpAddress, this, true);
463 return;
464 }
465 else {
466 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200467 //If the prefix is for a non-peer we need to ensure there's a path,
468 //and push one if there isn't.
469 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200470 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200471 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300472 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200473 pushedPaths.put(dstIpAddress, path);
474 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200475
476 path.incrementUsers();
477 prefixToPath.put(prefix, path);
478 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200479
480 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200481 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
482 }
483 }
484
Jonathan Hartabad6a52013-09-30 18:17:21 +1300485 private void addPrefixFlows(Prefix prefix, Interface egressInterface, MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700486 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300487 prefix, nextHopMacAddress);
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200488
489 //We only need one flow mod per switch, so pick one interface on each switch
490 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
491 for (Interface intf : interfaces.values()) {
492 if (!srcInterfaces.containsKey(intf.getDpid())
493 && intf != egressInterface) {
494 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200495 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200496 }
497
498 //Add a flow to rewrite mac for this prefix to all other border switches
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200499 for (Interface srcInterface : srcInterfaces.values()) {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200500 DataPath shortestPath;
501 if (topoRouteTopology == null) {
502 shortestPath = topoRouteService.getShortestPath(
503 srcInterface.getSwitchPort(),
504 egressInterface.getSwitchPort());
505 }
506 else {
507 shortestPath = topoRouteService.getTopoShortestPath(
508 topoRouteTopology, srcInterface.getSwitchPort(),
509 egressInterface.getSwitchPort());
510 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200511
512 if (shortestPath == null){
513 log.debug("Shortest path between {} and {} not found",
514 srcInterface.getSwitchPort(),
515 egressInterface.getSwitchPort());
516 return; // just quit here?
517 }
518
519 //Set up the flow mod
520 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
521 .getMessage(OFType.FLOW_MOD);
522
523 fm.setIdleTimeout((short)0)
524 .setHardTimeout((short)0)
525 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
526 .setCookie(MAC_RW_COOKIE)
527 .setCommand(OFFlowMod.OFPFC_ADD)
528 .setPriority(SDNIP_PRIORITY)
529 .setLengthU(OFFlowMod.MINIMUM_LENGTH
530 + OFActionDataLayerDestination.MINIMUM_LENGTH
531 + OFActionOutput.MINIMUM_LENGTH);
532
533 OFMatch match = new OFMatch();
534 match.setDataLayerType(Ethernet.TYPE_IPv4);
535 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
536
537 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
538 fm.setMatch(match);
539
540 //Set up MAC rewrite action
541 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartabad6a52013-09-30 18:17:21 +1300542 macRewriteAction.setDataLayerAddress(nextHopMacAddress.toBytes());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200543
544 //Set up output action
545 OFActionOutput outputAction = new OFActionOutput();
546 outputAction.setMaxLength((short)0xffff);
547 Port outputPort = shortestPath.flowEntries().get(0).outPort();
548 outputAction.setPort(outputPort.value());
549
550 List<OFAction> actions = new ArrayList<OFAction>();
551 actions.add(macRewriteAction);
552 actions.add(outputAction);
553 fm.setActions(actions);
554
Jonathan Hart1912afc2013-10-11 12:02:44 +1300555 pushedFlows.put(prefix, new PushedFlowMod(srcInterface.getDpid(), fm));
556 flowCache.write(srcInterface.getDpid(), fm);
557
558 /*
559 * XXX Rate limit hack!
560 * This should be solved properly by adding a rate limiting
561 * layer on top of the switches if we know they need it.
562 */
563 try {
Jonathan Hart9971e1c2013-09-17 10:47:40 +1200564 Thread.sleep(1);
Jonathan Hart65139e42013-09-13 16:52:25 +1200565 } catch (InterruptedException e) {
566 // TODO handle this properly
567 log.error("Interrupted", e);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200568 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200569 }
570 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200571
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200572 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200573 Prefix prefix = update.getPrefix();
574
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200575 if (ptree.remove(prefix, update.getRibEntry())) {
576 /*
577 * Only delete flows if an entry was actually removed from the trie.
578 * If no entry was removed, the <prefix, nexthop> wasn't there so
579 * it's probably already been removed and we don't need to do anything
580 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200581 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200582 }
583 }
584
585 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
586 deletePrefixFlows(prefix);
587
588 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200589
Jonathan Hart309889c2013-08-13 23:26:24 +1200590 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
591 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200592 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200593
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200594 if (path != null) {
595 //path could be null if we added to the Ptree but didn't push
596 //flows yet because we were waiting to resolve ARP
Jonathan Hart309889c2013-08-13 23:26:24 +1200597
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200598 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200599 if (path.getUsers() <= 0 && !path.isPermanent()) {
600 deletePath(path);
601 pushedPaths.remove(path.getDstIpAddress());
602 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200603 }
604 }
605 }
606
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200607 private void deletePrefixFlows(Prefix prefix) {
608 log.debug("Deleting flows for prefix {}", prefix);
609
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200610 Collection<PushedFlowMod> pushedFlowMods
611 = pushedFlows.removeAll(prefix);
612
613 for (PushedFlowMod pfm : pushedFlowMods) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200614 if (log.isTraceEnabled()) {
615 log.trace("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
616 new Object[] {HexString.toHexString(pfm.getDpid()),
617 pfm.getFlowMod().getMatch().getNetworkDestination() +
618 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
619 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
620 .getDataLayerAddress())});
621 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200622
623 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
624 }
625 }
626
627 private void deletePath(Path path) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200628 log.debug("Deleting flows for path to {}",
629 path.getDstIpAddress().getHostAddress());
630
Jonathan Hart309889c2013-08-13 23:26:24 +1200631 for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200632 if (log.isTraceEnabled()) {
633 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
634 new Object[] {HexString.toHexString(pfm.getDpid()),
635 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
636 });
637 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200638
639 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
640 }
641 }
642
643 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
Jonathan Hart1912afc2013-10-11 12:02:44 +1300644 flowCache.delete(dpid, addFlowMod);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200645 }
646
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200647 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200648 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200649
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700650 /*
651 * On startup we need to calculate a full mesh of paths between all gateway
652 * switches
653 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200654 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700655 //For each border router, calculate and install a path from every other
656 //border switch to said border router. However, don't install the entry
657 //in to the first hop switch, as we need to install an entry to rewrite
658 //for each prefix received. This will be done later when prefixes have
659 //actually been received.
660
Jonathan Hartc824ad02013-07-03 15:58:45 +1200661 for (BgpPeer peer : bgpPeers.values()) {
662 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200663
Jonathan Hart309889c2013-08-13 23:26:24 +1200664 //We know there's not already a Path here pushed, because this is
665 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200666 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200667 path.setPermanent();
668
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200669 //See if we know the MAC address of the peer. If not we can't
670 //do anything until we learn it
Jonathan Hartabad6a52013-09-30 18:17:21 +1300671 MACAddress macAddress = proxyArp.getMacAddress(peer.getIpAddress());
672 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200673 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
674 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200675 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700676
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200677 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
678 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700679 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200680
681 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300682 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700683 }
684 }
685
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200686 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200687 Interface dstInterface = path.getDstInterface();
688
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200689 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
690 dstMacAddress);
691
Jonathan Hart309889c2013-08-13 23:26:24 +1200692 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
693
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200694 for (Interface srcInterface : interfaces.values()) {
695 if (dstInterface.equals(srcInterface.getName())){
696 continue;
697 }
698
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200699 DataPath shortestPath;
700 if (topoRouteTopology == null) {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200701 shortestPath = topoRouteService.getShortestPath(
702 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
703 }
704 else {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200705 shortestPath = topoRouteService.getTopoShortestPath(topoRouteTopology,
706 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
707 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200708
709 if (shortestPath == null){
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200710 log.warn("Shortest path between {} and {} not found",
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200711 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200712 return;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200713 }
714
Jonathan Hart1912afc2013-10-11 12:02:44 +1300715 List<PushedFlowMod> pushedFlowMods = installPath(shortestPath.flowEntries(), dstMacAddress);
716 pushedFlows.addAll(pushedFlowMods);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200717 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200718
719 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200720 }
721
Jonathan Hart309889c2013-08-13 23:26:24 +1200722 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
723 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
724
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700725 //Set up the flow mod
726 OFFlowMod fm =
727 (OFFlowMod) floodlightProvider.getOFMessageFactory()
728 .getMessage(OFType.FLOW_MOD);
729
730 OFActionOutput action = new OFActionOutput();
731 action.setMaxLength((short)0xffff);
732 List<OFAction> actions = new ArrayList<OFAction>();
733 actions.add(action);
734
735 fm.setIdleTimeout((short)0)
736 .setHardTimeout((short)0)
737 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
738 .setCookie(L2_FWD_COOKIE)
739 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hartbdc87462013-09-24 15:03:23 +1200740 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700741 .setActions(actions)
742 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
743
744 //Don't push the first flow entry. We need to push entries in the
745 //first switch based on IP prefix which we don't know yet.
746 for (int i = 1; i < flowEntries.size(); i++){
747 FlowEntry flowEntry = flowEntries.get(i);
748
749 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200750 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700751 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
752 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
753
754 fm.setMatch(match);
755
Jonathan Hart1912afc2013-10-11 12:02:44 +1300756 flowMods.add(new PushedFlowMod(flowEntry.dpid().value(), fm));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700757
Jonathan Hart1912afc2013-10-11 12:02:44 +1300758 flowCache.write(flowEntry.dpid().value(), fm);
759
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700760 try {
761 fm = fm.clone();
762 } catch (CloneNotSupportedException e1) {
763 log.error("Failure cloning flow mod", e1);
764 }
765 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200766
767 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700768 }
769
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200770 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200771 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200772 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
773
774 DataPath path = topoRouteService.getShortestPath(
775 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
776
777 if (path == null){
778 log.debug("Unable to compute path for BGP traffic for {}",
779 bgpPeer.getIpAddress());
780 continue;
781 }
782
783 //Set up the flow mod
784 OFFlowMod fm =
785 (OFFlowMod) floodlightProvider.getOFMessageFactory()
786 .getMessage(OFType.FLOW_MOD);
787
788 OFActionOutput action = new OFActionOutput();
789 action.setMaxLength((short)0xffff);
790 List<OFAction> actions = new ArrayList<OFAction>();
791 actions.add(action);
792
793 fm.setIdleTimeout((short)0)
794 .setHardTimeout((short)0)
795 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
796 .setCookie(BGP_COOKIE)
797 .setCommand(OFFlowMod.OFPFC_ADD)
798 .setPriority(SDNIP_PRIORITY)
799 .setActions(actions)
800 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
801
802 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
803 OFMatch forwardMatchSrc = new OFMatch();
804
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200805 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
806 + "/32";
807 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
808 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200809
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200810 //Common match fields
811 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200812 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300813 //forwardMatchSrc.setTransportDestination(BGP_PORT);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200814 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
815 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
816
817
818 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
819
820 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
821 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
822
823 OFMatch forwardMatchDst = forwardMatchSrc.clone();
824
825 forwardMatchSrc.setTransportSource(BGP_PORT);
826 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
827 forwardMatchDst.setTransportDestination(BGP_PORT);
828 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
829
830 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
831 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
832
833 OFMatch reverseMatchDst = reverseMatchSrc.clone();
834
835 reverseMatchSrc.setTransportSource(BGP_PORT);
836 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
837 reverseMatchDst.setTransportDestination(BGP_PORT);
838 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
839
840 fm.setMatch(forwardMatchSrc);
841
Jonathan Hart38c84932013-08-10 17:49:27 +1200842 OFMatch forwardIcmpMatch = new OFMatch();
843 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
844 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
845 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
846 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
847
848 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
849 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
850 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
851
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200852 for (FlowEntry flowEntry : path.flowEntries()){
853 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
854 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200855 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200856 try {
857 forwardFlowModSrc = fm.clone();
858 forwardFlowModDst = fm.clone();
859 reverseFlowModSrc = fm.clone();
860 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200861 forwardIcmp = fm.clone();
862 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200863 } catch (CloneNotSupportedException e) {
864 log.warn("Clone failed", e);
865 continue;
866 }
867
868 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
869 forwardFlowModSrc.setMatch(forwardMatchSrc);
870 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
871 .setPort(flowEntry.outPort().value());
872
873 forwardMatchDst.setInputPort(flowEntry.inPort().value());
874 forwardFlowModDst.setMatch(forwardMatchDst);
875 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
876 .setPort(flowEntry.outPort().value());
877
878 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
879 reverseFlowModSrc.setMatch(reverseMatchSrc);
880 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
881 .setPort(flowEntry.inPort().value());
882
883 reverseMatchDst.setInputPort(flowEntry.outPort().value());
884 reverseFlowModDst.setMatch(reverseMatchDst);
885 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
886 .setPort(flowEntry.inPort().value());
887
Jonathan Hart38c84932013-08-10 17:49:27 +1200888 ((OFActionOutput)forwardIcmp.getActions().get(0))
889 .setPort(flowEntry.outPort().value());
890 forwardIcmp.setMatch(forwardIcmpMatch);
891
892 ((OFActionOutput)reverseIcmp.getActions().get(0))
893 .setPort(flowEntry.inPort().value());
894 reverseIcmp.setMatch(reverseIcmpMatch);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200895
Jonathan Hart1912afc2013-10-11 12:02:44 +1300896 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(6);
897 flowModList.add(forwardFlowModSrc);
898 flowModList.add(forwardFlowModDst);
899 flowModList.add(reverseFlowModSrc);
900 flowModList.add(reverseFlowModDst);
901 flowModList.add(forwardIcmp);
902 flowModList.add(reverseIcmp);
903 flowCache.write(flowEntry.dpid().value(), flowModList);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200904 }
905 }
906 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200907
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200908 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +1300909 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
910 log.debug("Received ARP response: {} => {}",
911 ipAddress.getHostAddress(), macAddress);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200912
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200913 /*
914 * We synchronize on this to prevent changes to the ptree while we're pushing
915 * flows to the switches. If the ptree changes, the ptree and switches
916 * could get out of sync.
917 */
918 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200919 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200920
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200921 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200922 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300923 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200924 path.getDstInterface().getSwitchPort()});
925 //These paths should always be to BGP peers. Paths to non-peers are
926 //handled once the first prefix is ready to push
927 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200928 //A path already got pushed to this endpoint while we were waiting
929 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200930 if (path.isPermanent()) {
931 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200932 }
933 }
934 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300935 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200936 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200937 }
938 }
939
Jonathan Hart309889c2013-08-13 23:26:24 +1200940 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
941
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200942 for (RibUpdate update : prefixesToPush) {
943 //These will always be adds
944
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200945 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200946 if (rib != null && rib.equals(update.getRibEntry())) {
947 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200948 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200949 //We only push prefix flows if the prefix is still in the ptree
950 //and the next hop is the same as our update. The prefix could
951 //have been removed while we were waiting for the ARP, or the
952 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200953 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200954 } else {
955 log.debug("Received ARP response, but {},{} is no longer in ptree",
956 update.getPrefix(), update.getRibEntry());
957 }
958 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200959 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200960 }
961
Jonathan Hartc82051c2013-08-24 15:12:20 +1200962 private void setupArpFlows() {
963 OFMatch match = new OFMatch();
964 match.setDataLayerType(Ethernet.TYPE_ARP);
965 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
966
967 OFFlowMod fm = new OFFlowMod();
968 fm.setMatch(match);
969
970 OFActionOutput action = new OFActionOutput();
971 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
972 action.setMaxLength((short)0xffff);
973 List<OFAction> actions = new ArrayList<OFAction>(1);
974 actions.add(action);
975 fm.setActions(actions);
976
977 fm.setIdleTimeout((short)0)
978 .setHardTimeout((short)0)
979 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
980 .setCookie(0)
981 .setCommand(OFFlowMod.OFPFC_ADD)
982 .setPriority(ARP_PRIORITY)
983 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
984
985 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +1300986 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +1200987 }
988 }
989
Jonathan Hartf886fa12013-09-18 14:46:29 +1200990 private void setupDefaultDropFlows() {
991 OFFlowMod fm = new OFFlowMod();
992 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +1200993 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Jonathan Hartf886fa12013-09-18 14:46:29 +1200994
995 fm.setIdleTimeout((short)0)
996 .setHardTimeout((short)0)
997 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
998 .setCookie(0)
999 .setCommand(OFFlowMod.OFPFC_ADD)
1000 .setPriority((short)0)
1001 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
1002
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001003 OFFlowMod fmLLDP;
1004 OFFlowMod fmBDDP;
1005 try {
1006 fmLLDP = fm.clone();
1007 fmBDDP = fm.clone();
1008 } catch (CloneNotSupportedException e1) {
1009 log.error("Error cloning flow mod", e1);
1010 return;
1011 }
1012
1013 OFMatch matchLLDP = new OFMatch();
1014 matchLLDP.setDataLayerType((short)0x8942);
1015 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1016 fmLLDP.setMatch(matchLLDP);
1017
1018 OFMatch matchBDDP = new OFMatch();
1019 matchBDDP.setDataLayerType((short)0x88cc);
1020 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1021 fmBDDP.setMatch(matchBDDP);
1022
1023 OFActionOutput action = new OFActionOutput();
1024 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1025 action.setMaxLength((short)0xffff);
1026 List<OFAction> actions = new ArrayList<OFAction>(1);
1027 actions.add(action);
1028
1029 fmLLDP.setActions(actions);
1030 fmBDDP.setActions(actions);
1031
1032 fmLLDP.setPriority(ARP_PRIORITY);
1033 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1034 fmBDDP.setPriority(ARP_PRIORITY);
1035 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1036
Jonathan Hart1912afc2013-10-11 12:02:44 +13001037 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1038 flowModList.add(fm);
1039 flowModList.add(fmLLDP);
1040 flowModList.add(fmBDDP);
1041
Jonathan Hartf886fa12013-09-18 14:46:29 +12001042 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001043 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001044 }
1045 }
1046
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001047 private void beginRouting(){
1048 log.debug("Topology is now ready, beginning routing function");
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001049 topoRouteTopology = topoRouteService.prepareShortestPathTopo();
1050
Jonathan Hartc82051c2013-08-24 15:12:20 +12001051 setupArpFlows();
Jonathan Hartf886fa12013-09-18 14:46:29 +12001052 setupDefaultDropFlows();
Jonathan Hartc82051c2013-08-24 15:12:20 +12001053
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001054 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001055 setupFullMesh();
Jonathan Harte7694532013-09-12 12:34:46 +12001056
1057 //Suppress link discovery on external-facing router ports
1058 for (Interface intf : interfaces.values()) {
1059 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1060 }
1061
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001062 bgpUpdatesExecutor.execute(new Runnable() {
1063 @Override
1064 public void run() {
1065 doUpdatesThread();
1066 }
1067 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001068 }
1069
1070 private void checkSwitchesConnected(){
1071 for (String dpid : switches){
1072 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1073 log.debug("Not all switches are here yet");
1074 return;
1075 }
1076 }
1077 switchesConnected = true;
1078 }
1079
Jonathan Hartc824ad02013-07-03 15:58:45 +12001080 //Actually we only need to go half way round to verify full mesh connectivity
1081 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001082 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001083 for (Interface dstInterface : interfaces.values()) {
1084 for (Interface srcInterface : interfaces.values()) {
1085 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001086 continue;
1087 }
1088
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001089 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001090 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001091
1092 if (shortestPath == null){
1093 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001094 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001095 return;
1096 }
1097 }
1098 }
1099 topologyReady = true;
1100 }
1101
1102 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001103 if (!switchesConnected){
1104 checkSwitchesConnected();
1105 }
1106 boolean oldTopologyReadyStatus = topologyReady;
1107 if (switchesConnected && !topologyReady){
1108 checkTopologyReady();
1109 }
1110 if (!oldTopologyReadyStatus && topologyReady){
1111 beginRouting();
1112 }
1113 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001114
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001115 private void doUpdatesThread() {
1116 boolean interrupted = false;
1117 try {
1118 while (true) {
1119 try {
1120 RibUpdate update = ribUpdates.take();
1121 switch (update.getOperation()){
1122 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001123 if (validateUpdate(update)) {
1124 processRibAdd(update);
1125 }
1126 else {
1127 log.debug("Rib UPDATE out of order: {} via {}",
1128 update.getPrefix(), update.getRibEntry().getNextHop());
1129 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001130 break;
1131 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001132 if (validateUpdate(update)) {
1133 processRibDelete(update);
1134 }
1135 else {
1136 log.debug("Rib DELETE out of order: {} via {}",
1137 update.getPrefix(), update.getRibEntry().getNextHop());
1138 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001139 break;
1140 }
1141 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001142 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001143 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001144 } catch (Exception e) {
1145 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001146 }
1147 }
1148 } finally {
1149 if (interrupted) {
1150 Thread.currentThread().interrupt();
1151 }
1152 }
1153 }
Jonathan Harte4c98692013-10-18 17:40:03 -07001154
1155 private boolean validateUpdate(RibUpdate update) {
1156 RibEntry newEntry = update.getRibEntry();
1157 RibEntry oldEntry = ptree.lookup(update.getPrefix());
1158
1159 //If there is no existing entry we must assume this is the most recent
1160 //update. However this might not always be the case as we might have a
1161 //POST then DELETE reordering.
1162 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1163 if (oldEntry == null) {
1164 return true;
1165 }
1166
1167 // This handles the case where routes are gathered in the initial
1168 // request because they don't have sequence number info
1169 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1170 return true;
1171 }
1172
1173 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1174 return true;
1175 }
1176 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1177 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1178 return true;
1179 }
1180 else {
1181 return false;
1182 }
1183 }
1184 else {
1185 return false;
1186 }
1187 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001188
1189 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001190 public void topologyChanged() {
1191 if (topologyReady) {
1192 return;
1193 }
1194
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001195 boolean refreshNeeded = false;
1196 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1197 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1198 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001199 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001200 refreshNeeded = true;
1201 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001202
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001203 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001204
Jonathan Hart98957bf2013-07-01 14:49:24 +12001205 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1206 synchronized (linkUpdates) {
1207 linkUpdates.add(ldu);
1208 }
1209 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001210 }
1211
Jonathan Hart64c0b202013-08-20 15:45:07 +12001212 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001213 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001214 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001215 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001216
1217 @Override
1218 public void addedSwitch(IOFSwitch sw) {
1219 if (!topologyReady) {
1220 sw.clearAllFlowMods();
1221 }
Jonathan Hart1912afc2013-10-11 12:02:44 +13001222
1223 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001224 }
1225
1226 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001227 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001228
1229 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001230 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001231
1232 @Override
1233 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001234 return "BgpRoute";
1235 }
1236
1237 /*
1238 * ILayer3InfoService methods
1239 */
1240
1241 @Override
1242 public boolean isInterfaceAddress(InetAddress address) {
1243 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1244 return (intf != null && intf.getIpAddress().equals(address));
1245 }
1246
1247 @Override
1248 public boolean inConnectedNetwork(InetAddress address) {
1249 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1250 return (intf != null && !intf.getIpAddress().equals(address));
1251 }
1252
1253 @Override
1254 public boolean fromExternalNetwork(long inDpid, short inPort) {
1255 for (Interface intf : interfaces.values()) {
1256 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1257 return true;
1258 }
1259 }
1260 return false;
1261 }
1262
1263 @Override
1264 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1265 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1266 }
1267
1268 @Override
1269 public boolean hasLayer3Configuration() {
1270 return !interfaces.isEmpty();
1271 }
1272
1273 @Override
1274 public MACAddress getRouterMacAddress() {
1275 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001276 }
Jonathan Hart5afde492013-10-01 12:30:53 +13001277
1278 /*
1279 * TODO This is a hack to get the REST API to work for ProxyArpManager.
1280 * The REST API is currently tied to the Floodlight module system and we
1281 * need to separate it to allow ONOS modules to use it. For now we will
1282 * proxy calls through to the ProxyArpManager (which is not a Floodlight
1283 * module) through this class which is a module.
1284 */
1285 @Override
1286 public MACAddress getMacAddress(InetAddress ipAddress) {
1287 return proxyArp.getMacAddress(ipAddress);
1288 }
1289
1290 @Override
1291 public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
1292 boolean retry) {
1293 proxyArp.sendArpRequest(ipAddress, requester, retry);
1294 }
1295
1296 @Override
1297 public List<String> getMappings() {
1298 return proxyArp.getMappings();
1299 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001300}