blob: 960d00136d57ae3767a6dd02d6ec761f8c0a90ac [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 Hartc7ca35d2013-06-25 20:54:25 +120043import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070044import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070045import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120046import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070048import net.onrc.onos.ofcontroller.util.Port;
49import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080050import net.sf.json.JSONArray;
51import net.sf.json.JSONObject;
52import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080053
Jonathan Hartd1f23252013-06-13 15:17:05 +120054import org.codehaus.jackson.JsonParseException;
55import org.codehaus.jackson.map.JsonMappingException;
56import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070057import org.openflow.protocol.OFFlowMod;
58import org.openflow.protocol.OFMatch;
59import org.openflow.protocol.OFMessage;
60import 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 Hart08ee8522013-09-22 17:34:43 +120079 IOFSwitchListener, ILayer3InfoService {
pingping-lina2cbfad2013-03-07 08:39:21 +080080
81 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
82
83 protected IFloodlightProviderService floodlightProvider;
84 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070085 protected ITopoRouteService topoRouteService;
Jonathan Harte7694532013-09-12 12:34:46 +120086 protected ILinkDiscoveryService linkDiscoveryService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070087 protected IRestApiService restApi;
88
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120089 protected ProxyArpManager proxyArp;
90
Jonathan Hart29b972d2013-08-12 23:43:51 +120091 protected IPatriciaTrie<RibEntry> ptree;
Jonathan Hartabf10222013-08-13 10:19:34 +120092 protected IPatriciaTrie<Interface> interfacePtrie;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120093 protected BlockingQueue<RibUpdate> ribUpdates;
94
Jonathan Hart61ba9372013-05-19 20:10:29 -070095 protected String bgpdRestIp;
96 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120097 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070098
99 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
100 //the controller/OS should hand out cookie IDs to prevent conflicts.
101 protected final long APP_COOKIE = 0xa0000000000000L;
102 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
103 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
104 //Cookie for flows in ingress switches that rewrite the MAC address
105 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200106 //Cookie for flows that setup BGP paths
107 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200108 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
109 //need to be higher priority than this otherwise the rewrite may not get done
110 protected final short SDNIP_PRIORITY = 10;
Jonathan Hartc82051c2013-08-24 15:12:20 +1200111 protected final short ARP_PRIORITY = 20;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700112
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200113 protected final short BGP_PORT = 179;
114
Jonathan Hart98957bf2013-07-01 14:49:24 +1200115 protected final int TOPO_DETECTION_WAIT = 2; //seconds
116
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200117 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200118 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200119 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200120 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200121 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart2f790d22013-08-15 14:01:24 +1200122 protected MACAddress bgpdMacAddress;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200123
124 //True when all switches have connected
125 protected volatile boolean switchesConnected = false;
126 //True when we have a full mesh of shortest paths between gateways
127 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200128
Jonathan Hart98957bf2013-07-01 14:49:24 +1200129 protected ArrayList<LDUpdate> linkUpdates;
130 protected SingletonTask topologyChangeDetectorTask;
131
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200132 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200133
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200134 protected Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200135
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200136 protected ExecutorService bgpUpdatesExecutor;
137
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200138 protected Map<InetAddress, Path> pushedPaths;
139 protected Map<Prefix, Path> prefixToPath;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200140 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200141
142 protected volatile Map<Long, ?> topoRouteTopology = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200143
Jonathan Hart98957bf2013-07-01 14:49:24 +1200144 protected class TopologyChangeDetector implements Runnable {
145 @Override
146 public void run() {
147 log.debug("Running topology change detection task");
148 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200149 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200150 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
151
152 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200153
154 Iterator<LDUpdate> it = linkUpdates.iterator();
155 while (it.hasNext()){
156 LDUpdate ldu = it.next();
157 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
158 ldu.getDst(), ldu.getDstPort());
159
160 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200161 it.remove();
162 }
163 }
164 }
165
Jonathan Hart64c0b202013-08-20 15:45:07 +1200166 if (!topologyReady) {
167 if (linkUpdates.isEmpty()){
168 //All updates have been seen in network map.
169 //We can check if topology is ready
170 log.debug("No known changes outstanding. Checking topology now");
171 checkStatus();
172 }
173 else {
174 //We know of some link updates that haven't propagated to the database yet
175 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
176 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
177 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200178 }
179 }
180 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700181
Jonathan Hartd1f23252013-06-13 15:17:05 +1200182 private void readGatewaysConfiguration(String gatewaysFilename){
183 File gatewaysFile = new File(gatewaysFilename);
184 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700185
Jonathan Hartd1f23252013-06-13 15:17:05 +1200186 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200187 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
188
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200189 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200190 interfaces = new HashMap<String, Interface>();
191 for (Interface intf : config.getInterfaces()){
192 interfaces.put(intf.getName(), intf);
193 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200194 bgpPeers = new HashMap<InetAddress, BgpPeer>();
195 for (BgpPeer peer : config.getPeers()){
196 bgpPeers.put(peer.getIpAddress(), peer);
197 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200198
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200199 bgpdAttachmentPoint = new SwitchPort(
200 new Dpid(config.getBgpdAttachmentDpid()),
201 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200202
Jonathan Hart2f790d22013-08-15 14:01:24 +1200203 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200204 } catch (JsonParseException e) {
205 log.error("Error in JSON file", e);
206 System.exit(1);
207 } catch (JsonMappingException e) {
208 log.error("Error in JSON file", e);
209 System.exit(1);
210 } catch (IOException e) {
211 log.error("Error reading JSON file", e);
212 System.exit(1);
213 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200214
215 //Populate the interface Patricia Trie
216 for (Interface intf : interfaces.values()) {
217 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
218 interfacePtrie.put(prefix, intf);
219 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700220 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800221
222 @Override
223 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700224 Collection<Class<? extends IFloodlightService>> l
225 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800226 l.add(IBgpRouteService.class);
227 return l;
228 }
229
230 @Override
231 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700232 Map<Class<? extends IFloodlightService>, IFloodlightService> m
233 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800234 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800235 return m;
236 }
237
pingping-lina2cbfad2013-03-07 08:39:21 +0800238 @Override
239 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700240 Collection<Class<? extends IFloodlightService>> l
241 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800242 l.add(IFloodlightProviderService.class);
243 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700244 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800245 return l;
246 }
247
248 @Override
249 public void init(FloodlightModuleContext context)
250 throws FloodlightModuleException {
251
Jonathan Hart29b972d2013-08-12 23:43:51 +1200252 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200253 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200254
255 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200256
pingping-lina2cbfad2013-03-07 08:39:21 +0800257 // Register floodlight provider and REST handler.
258 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800259 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200260 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200261 restApi = context.getServiceImpl(IRestApiService.class);
262
263 //TODO We'll initialise this here for now, but it should really be done as
264 //part of the controller core
Jonathan Hart08ee8522013-09-22 17:34:43 +1200265 proxyArp = new ProxyArpManager(floodlightProvider, topology, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800266
Jonathan Hart98957bf2013-07-01 14:49:24 +1200267 linkUpdates = new ArrayList<LDUpdate>();
268 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
269 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700270
271 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200272
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200273 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200274 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
275 HashMultimap.<InetAddress, RibUpdate>create());
276
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200277 pushedPaths = new HashMap<InetAddress, Path>();
278 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200279 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
280
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200281 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
282 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
283
Jonathan Hart61ba9372013-05-19 20:10:29 -0700284 //Read in config values
285 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
286 if (bgpdRestIp == null){
287 log.error("BgpdRestIp property not found in config file");
288 System.exit(1);
289 }
290 else {
291 log.info("BgpdRestIp set to {}", bgpdRestIp);
292 }
293
294 routerId = context.getConfigParams(this).get("RouterId");
295 if (routerId == null){
296 log.error("RouterId property not found in config file");
297 System.exit(1);
298 }
299 else {
300 log.info("RouterId set to {}", routerId);
301 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200302
Jonathan Hart9575cb62013-07-05 13:43:49 +1200303 String configFilenameParameter = context.getConfigParams(this).get("configfile");
304 if (configFilenameParameter != null){
305 configFilename = configFilenameParameter;
306 }
307 log.debug("Config file set to {}", configFilename);
308
309 readGatewaysConfiguration(configFilename);
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);
Jonathan Hart08ee8522013-09-22 17:34:43 +1200466 calculateAndPushPath(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));
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200482
483 //We only need one flow mod per switch, so pick one interface on each switch
484 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
485 for (Interface intf : interfaces.values()) {
486 if (!srcInterfaces.containsKey(intf.getDpid())
487 && intf != egressInterface) {
488 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200489 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200490 }
491
492 //Add a flow to rewrite mac for this prefix to all other border switches
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200493 for (Interface srcInterface : srcInterfaces.values()) {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200494 DataPath shortestPath;
495 if (topoRouteTopology == null) {
496 shortestPath = topoRouteService.getShortestPath(
497 srcInterface.getSwitchPort(),
498 egressInterface.getSwitchPort());
499 }
500 else {
501 shortestPath = topoRouteService.getTopoShortestPath(
502 topoRouteTopology, srcInterface.getSwitchPort(),
503 egressInterface.getSwitchPort());
504 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200505
506 if (shortestPath == null){
507 log.debug("Shortest path between {} and {} not found",
508 srcInterface.getSwitchPort(),
509 egressInterface.getSwitchPort());
510 return; // just quit here?
511 }
512
513 //Set up the flow mod
514 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
515 .getMessage(OFType.FLOW_MOD);
516
517 fm.setIdleTimeout((short)0)
518 .setHardTimeout((short)0)
519 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
520 .setCookie(MAC_RW_COOKIE)
521 .setCommand(OFFlowMod.OFPFC_ADD)
522 .setPriority(SDNIP_PRIORITY)
523 .setLengthU(OFFlowMod.MINIMUM_LENGTH
524 + OFActionDataLayerDestination.MINIMUM_LENGTH
525 + OFActionOutput.MINIMUM_LENGTH);
526
527 OFMatch match = new OFMatch();
528 match.setDataLayerType(Ethernet.TYPE_IPv4);
529 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
530
531 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
532 fm.setMatch(match);
533
534 //Set up MAC rewrite action
535 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
536 macRewriteAction.setDataLayerAddress(nextHopMacAddress);
537
538 //Set up output action
539 OFActionOutput outputAction = new OFActionOutput();
540 outputAction.setMaxLength((short)0xffff);
541 Port outputPort = shortestPath.flowEntries().get(0).outPort();
542 outputAction.setPort(outputPort.value());
543
544 List<OFAction> actions = new ArrayList<OFAction>();
545 actions.add(macRewriteAction);
546 actions.add(outputAction);
547 fm.setActions(actions);
548
549 //Write to switch
550 IOFSwitch sw = floodlightProvider.getSwitches()
551 .get(srcInterface.getDpid());
552
553 if (sw == null){
554 log.warn("Switch not found when pushing flow mod");
555 continue;
556 }
557
558 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
559
560 List<OFMessage> msglist = new ArrayList<OFMessage>();
561 msglist.add(fm);
562 try {
563 sw.write(msglist, null);
564 sw.flush();
Jonathan Hart08ee8522013-09-22 17:34:43 +1200565
566 /*
567 * XXX Rate limit hack!
568 * This should be solved properly by adding a rate limiting
569 * layer on top of the switches if we know they need it.
570 */
Jonathan Hart9971e1c2013-09-17 10:47:40 +1200571 Thread.sleep(1);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200572 } catch (IOException e) {
573 log.error("Failure writing flow mod", e);
Jonathan Hart65139e42013-09-13 16:52:25 +1200574 } catch (InterruptedException e) {
575 // TODO handle this properly
576 log.error("Interrupted", e);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200577 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200578 }
579 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200580
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200581 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200582 Prefix prefix = update.getPrefix();
583
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200584 if (ptree.remove(prefix, update.getRibEntry())) {
585 /*
586 * Only delete flows if an entry was actually removed from the trie.
587 * If no entry was removed, the <prefix, nexthop> wasn't there so
588 * it's probably already been removed and we don't need to do anything
589 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200590 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200591 }
592 }
593
594 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
595 deletePrefixFlows(prefix);
596
597 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200598
Jonathan Hart309889c2013-08-13 23:26:24 +1200599 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
600 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200601 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200602
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200603 if (path != null) {
604 //path could be null if we added to the Ptree but didn't push
605 //flows yet because we were waiting to resolve ARP
Jonathan Hart309889c2013-08-13 23:26:24 +1200606
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200607 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200608 if (path.getUsers() <= 0 && !path.isPermanent()) {
609 deletePath(path);
610 pushedPaths.remove(path.getDstIpAddress());
611 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200612 }
613 }
614 }
615
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200616 private void deletePrefixFlows(Prefix prefix) {
617 log.debug("Deleting flows for prefix {}", prefix);
618
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200619 Collection<PushedFlowMod> pushedFlowMods
620 = pushedFlows.removeAll(prefix);
621
622 for (PushedFlowMod pfm : pushedFlowMods) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200623 if (log.isTraceEnabled()) {
624 log.trace("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
625 new Object[] {HexString.toHexString(pfm.getDpid()),
626 pfm.getFlowMod().getMatch().getNetworkDestination() +
627 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
628 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
629 .getDataLayerAddress())});
630 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200631
632 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
633 }
634 }
635
636 private void deletePath(Path path) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200637 log.debug("Deleting flows for path to {}",
638 path.getDstIpAddress().getHostAddress());
639
Jonathan Hart309889c2013-08-13 23:26:24 +1200640 for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200641 if (log.isTraceEnabled()) {
642 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
643 new Object[] {HexString.toHexString(pfm.getDpid()),
644 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
645 });
646 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200647
648 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
649 }
650 }
651
652 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
653 addFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
654 .setOutPort(OFPort.OFPP_NONE)
655 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
656
657 addFlowMod.getActions().clear();
658
659 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
660 if (sw == null) {
661 log.warn("Switch not found when pushing delete flow mod");
662 return;
663 }
664
665 try {
666 sw.write(addFlowMod, null);
667 sw.flush();
668 } catch (IOException e) {
669 log.error("Failure writing flow mod", e);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200670 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200671 }
672
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200673 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200674 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200675
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700676 /*
677 * On startup we need to calculate a full mesh of paths between all gateway
678 * switches
679 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200680 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700681 //For each border router, calculate and install a path from every other
682 //border switch to said border router. However, don't install the entry
683 //in to the first hop switch, as we need to install an entry to rewrite
684 //for each prefix received. This will be done later when prefixes have
685 //actually been received.
686
Jonathan Hartc824ad02013-07-03 15:58:45 +1200687 for (BgpPeer peer : bgpPeers.values()) {
688 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200689
Jonathan Hart309889c2013-08-13 23:26:24 +1200690 //We know there's not already a Path here pushed, because this is
691 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200692 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200693 path.setPermanent();
694
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200695 //See if we know the MAC address of the peer. If not we can't
696 //do anything until we learn it
697 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
698 if (mac == null) {
699 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
700 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200701 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700702
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200703 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
704 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700705 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200706
707 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hart08ee8522013-09-22 17:34:43 +1200708 calculateAndPushPath(path, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700709 }
710 }
711
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200712 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200713 Interface dstInterface = path.getDstInterface();
714
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200715 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
716 dstMacAddress);
717
Jonathan Hart309889c2013-08-13 23:26:24 +1200718 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
719
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200720 for (Interface srcInterface : interfaces.values()) {
721 if (dstInterface.equals(srcInterface.getName())){
722 continue;
723 }
724
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200725 DataPath shortestPath;
726 if (topoRouteTopology == null) {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200727 shortestPath = topoRouteService.getShortestPath(
728 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
729 }
730 else {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200731 shortestPath = topoRouteService.getTopoShortestPath(topoRouteTopology,
732 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
733 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200734
735 if (shortestPath == null){
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200736 log.warn("Shortest path between {} and {} not found",
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200737 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200738 return;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200739 }
740
Jonathan Hart309889c2013-08-13 23:26:24 +1200741 pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200742 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200743
744 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200745 }
746
Jonathan Hart309889c2013-08-13 23:26:24 +1200747 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
748 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
749
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700750 //Set up the flow mod
751 OFFlowMod fm =
752 (OFFlowMod) floodlightProvider.getOFMessageFactory()
753 .getMessage(OFType.FLOW_MOD);
754
755 OFActionOutput action = new OFActionOutput();
756 action.setMaxLength((short)0xffff);
757 List<OFAction> actions = new ArrayList<OFAction>();
758 actions.add(action);
759
760 fm.setIdleTimeout((short)0)
761 .setHardTimeout((short)0)
762 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
763 .setCookie(L2_FWD_COOKIE)
764 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hartbdc87462013-09-24 15:03:23 +1200765 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700766 .setActions(actions)
767 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
768
769 //Don't push the first flow entry. We need to push entries in the
770 //first switch based on IP prefix which we don't know yet.
771 for (int i = 1; i < flowEntries.size(); i++){
772 FlowEntry flowEntry = flowEntries.get(i);
773
774 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200775 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700776 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
777 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
778
779 fm.setMatch(match);
780
781 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
782
783 if (sw == null){
784 log.warn("Switch not found when pushing flow mod");
785 continue;
786 }
787
Jonathan Hart309889c2013-08-13 23:26:24 +1200788 flowMods.add(new PushedFlowMod(sw.getId(), fm));
789
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700790 List<OFMessage> msglist = new ArrayList<OFMessage>();
791 msglist.add(fm);
792 try {
793 sw.write(msglist, null);
794 sw.flush();
795 } catch (IOException e) {
796 log.error("Failure writing flow mod", e);
797 }
798
799 try {
800 fm = fm.clone();
801 } catch (CloneNotSupportedException e1) {
802 log.error("Failure cloning flow mod", e1);
803 }
804 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200805
806 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700807 }
808
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200809 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200810 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200811 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
812
813 DataPath path = topoRouteService.getShortestPath(
814 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
815
816 if (path == null){
817 log.debug("Unable to compute path for BGP traffic for {}",
818 bgpPeer.getIpAddress());
819 continue;
820 }
821
822 //Set up the flow mod
823 OFFlowMod fm =
824 (OFFlowMod) floodlightProvider.getOFMessageFactory()
825 .getMessage(OFType.FLOW_MOD);
826
827 OFActionOutput action = new OFActionOutput();
828 action.setMaxLength((short)0xffff);
829 List<OFAction> actions = new ArrayList<OFAction>();
830 actions.add(action);
831
832 fm.setIdleTimeout((short)0)
833 .setHardTimeout((short)0)
834 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
835 .setCookie(BGP_COOKIE)
836 .setCommand(OFFlowMod.OFPFC_ADD)
837 .setPriority(SDNIP_PRIORITY)
838 .setActions(actions)
839 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
840
841 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
842 OFMatch forwardMatchSrc = new OFMatch();
843
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200844 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
845 + "/32";
846 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
847 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200848
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200849 //Common match fields
850 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200851 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
852 forwardMatchSrc.setTransportDestination(BGP_PORT);
853 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
854 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
855
856
857 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
858
859 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
860 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
861
862 OFMatch forwardMatchDst = forwardMatchSrc.clone();
863
864 forwardMatchSrc.setTransportSource(BGP_PORT);
865 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
866 forwardMatchDst.setTransportDestination(BGP_PORT);
867 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
868
869 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
870 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
871
872 OFMatch reverseMatchDst = reverseMatchSrc.clone();
873
874 reverseMatchSrc.setTransportSource(BGP_PORT);
875 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
876 reverseMatchDst.setTransportDestination(BGP_PORT);
877 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
878
879 fm.setMatch(forwardMatchSrc);
880
Jonathan Hart38c84932013-08-10 17:49:27 +1200881 OFMatch forwardIcmpMatch = new OFMatch();
882 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
883 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
884 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
885 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
886
887 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
888 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
889 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
890
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200891 for (FlowEntry flowEntry : path.flowEntries()){
892 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
893 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200894 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200895 try {
896 forwardFlowModSrc = fm.clone();
897 forwardFlowModDst = fm.clone();
898 reverseFlowModSrc = fm.clone();
899 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200900 forwardIcmp = fm.clone();
901 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200902 } catch (CloneNotSupportedException e) {
903 log.warn("Clone failed", e);
904 continue;
905 }
906
907 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
908 forwardFlowModSrc.setMatch(forwardMatchSrc);
909 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
910 .setPort(flowEntry.outPort().value());
911
912 forwardMatchDst.setInputPort(flowEntry.inPort().value());
913 forwardFlowModDst.setMatch(forwardMatchDst);
914 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
915 .setPort(flowEntry.outPort().value());
916
917 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
918 reverseFlowModSrc.setMatch(reverseMatchSrc);
919 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
920 .setPort(flowEntry.inPort().value());
921
922 reverseMatchDst.setInputPort(flowEntry.outPort().value());
923 reverseFlowModDst.setMatch(reverseMatchDst);
924 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
925 .setPort(flowEntry.inPort().value());
926
Jonathan Hart38c84932013-08-10 17:49:27 +1200927 ((OFActionOutput)forwardIcmp.getActions().get(0))
928 .setPort(flowEntry.outPort().value());
929 forwardIcmp.setMatch(forwardIcmpMatch);
930
931 ((OFActionOutput)reverseIcmp.getActions().get(0))
932 .setPort(flowEntry.inPort().value());
933 reverseIcmp.setMatch(reverseIcmpMatch);
934
935
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200936 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
937
Jonathan Hart38c84932013-08-10 17:49:27 +1200938 if (sw == null) {
939 log.warn("Switch not found when pushing BGP paths");
940 return;
941 }
942
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200943 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
944 msgList.add(forwardFlowModSrc);
945 msgList.add(forwardFlowModDst);
946 msgList.add(reverseFlowModSrc);
947 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +1200948 msgList.add(forwardIcmp);
949 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200950
951 try {
952 sw.write(msgList, null);
953 sw.flush();
954 } catch (IOException e) {
955 log.error("Failure writing flow mod", e);
956 }
957 }
958 }
959 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200960
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200961 @Override
962 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
963 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
964 MACAddress.valueOf(macAddress).toString());
965
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200966 /*
967 * We synchronize on this to prevent changes to the ptree while we're pushing
968 * flows to the switches. If the ptree changes, the ptree and switches
969 * could get out of sync.
970 */
971 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200972 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200973
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200974 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200975 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200976 path.getDstIpAddress().getHostAddress(),
Jonathan Hart309889c2013-08-13 23:26:24 +1200977 MACAddress.valueOf(macAddress),
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200978 path.getDstInterface().getSwitchPort()});
979 //These paths should always be to BGP peers. Paths to non-peers are
980 //handled once the first prefix is ready to push
981 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200982 //A path already got pushed to this endpoint while we were waiting
983 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200984 if (path.isPermanent()) {
985 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200986 }
987 }
988 else {
Jonathan Hart08ee8522013-09-22 17:34:43 +1200989 calculateAndPushPath(path, MACAddress.valueOf(macAddress));
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200990 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200991 }
992 }
993
Jonathan Hart309889c2013-08-13 23:26:24 +1200994 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
995
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200996 for (RibUpdate update : prefixesToPush) {
997 //These will always be adds
998
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200999 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001000 if (rib != null && rib.equals(update.getRibEntry())) {
1001 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001002 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001003 //We only push prefix flows if the prefix is still in the ptree
1004 //and the next hop is the same as our update. The prefix could
1005 //have been removed while we were waiting for the ARP, or the
1006 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +12001007 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001008 } else {
1009 log.debug("Received ARP response, but {},{} is no longer in ptree",
1010 update.getPrefix(), update.getRibEntry());
1011 }
1012 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001013 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001014 }
1015
Jonathan Hartc82051c2013-08-24 15:12:20 +12001016 private void setupArpFlows() {
1017 OFMatch match = new OFMatch();
1018 match.setDataLayerType(Ethernet.TYPE_ARP);
1019 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1020
1021 OFFlowMod fm = new OFFlowMod();
1022 fm.setMatch(match);
1023
1024 OFActionOutput action = new OFActionOutput();
1025 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1026 action.setMaxLength((short)0xffff);
1027 List<OFAction> actions = new ArrayList<OFAction>(1);
1028 actions.add(action);
1029 fm.setActions(actions);
1030
1031 fm.setIdleTimeout((short)0)
1032 .setHardTimeout((short)0)
1033 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1034 .setCookie(0)
1035 .setCommand(OFFlowMod.OFPFC_ADD)
1036 .setPriority(ARP_PRIORITY)
1037 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1038
1039 for (String strdpid : switches){
1040 IOFSwitch sw = floodlightProvider.getSwitches().get(HexString.toLong(strdpid));
1041 if (sw == null) {
1042 log.debug("Couldn't find switch to push ARP flow");
1043 }
1044 else {
1045 try {
1046 sw.write(fm, null);
1047 } catch (IOException e) {
1048 log.warn("Failure writing ARP flow to switch", e);
1049 }
1050 }
1051 }
1052 }
1053
Jonathan Hartf886fa12013-09-18 14:46:29 +12001054 private void setupDefaultDropFlows() {
1055 OFFlowMod fm = new OFFlowMod();
1056 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001057 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Jonathan Hartf886fa12013-09-18 14:46:29 +12001058
1059 fm.setIdleTimeout((short)0)
1060 .setHardTimeout((short)0)
1061 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1062 .setCookie(0)
1063 .setCommand(OFFlowMod.OFPFC_ADD)
1064 .setPriority((short)0)
1065 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
1066
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001067 OFFlowMod fmLLDP;
1068 OFFlowMod fmBDDP;
1069 try {
1070 fmLLDP = fm.clone();
1071 fmBDDP = fm.clone();
1072 } catch (CloneNotSupportedException e1) {
1073 log.error("Error cloning flow mod", e1);
1074 return;
1075 }
1076
1077 OFMatch matchLLDP = new OFMatch();
1078 matchLLDP.setDataLayerType((short)0x8942);
1079 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1080 fmLLDP.setMatch(matchLLDP);
1081
1082 OFMatch matchBDDP = new OFMatch();
1083 matchBDDP.setDataLayerType((short)0x88cc);
1084 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1085 fmBDDP.setMatch(matchBDDP);
1086
1087 OFActionOutput action = new OFActionOutput();
1088 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1089 action.setMaxLength((short)0xffff);
1090 List<OFAction> actions = new ArrayList<OFAction>(1);
1091 actions.add(action);
1092
1093 fmLLDP.setActions(actions);
1094 fmBDDP.setActions(actions);
1095
1096 fmLLDP.setPriority(ARP_PRIORITY);
1097 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1098 fmBDDP.setPriority(ARP_PRIORITY);
1099 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1100
Jonathan Hartf886fa12013-09-18 14:46:29 +12001101 for (String strdpid : switches){
1102 IOFSwitch sw = floodlightProvider.getSwitches().get(HexString.toLong(strdpid));
1103 if (sw == null) {
1104 log.debug("Couldn't find switch to push default deny flow");
1105 }
1106 else {
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001107 List<OFMessage> msgList = new ArrayList<OFMessage>();
1108 msgList.add(fm);
1109 msgList.add(fmLLDP);
1110 msgList.add(fmBDDP);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001111 try {
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001112 sw.write(msgList, null);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001113 } catch (IOException e) {
1114 log.warn("Failure writing default deny flow to switch", e);
1115 }
1116 }
1117 }
1118 }
1119
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001120 private void beginRouting(){
1121 log.debug("Topology is now ready, beginning routing function");
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001122 topoRouteTopology = topoRouteService.prepareShortestPathTopo();
1123
Jonathan Hartc82051c2013-08-24 15:12:20 +12001124 setupArpFlows();
Jonathan Hartf886fa12013-09-18 14:46:29 +12001125 setupDefaultDropFlows();
Jonathan Hartc82051c2013-08-24 15:12:20 +12001126
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001127 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001128 setupFullMesh();
Jonathan Harte7694532013-09-12 12:34:46 +12001129
1130 //Suppress link discovery on external-facing router ports
1131 for (Interface intf : interfaces.values()) {
1132 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1133 }
1134
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001135 bgpUpdatesExecutor.execute(new Runnable() {
1136 @Override
1137 public void run() {
1138 doUpdatesThread();
1139 }
1140 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001141 }
1142
1143 private void checkSwitchesConnected(){
1144 for (String dpid : switches){
1145 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1146 log.debug("Not all switches are here yet");
1147 return;
1148 }
1149 }
1150 switchesConnected = true;
1151 }
1152
Jonathan Hartc824ad02013-07-03 15:58:45 +12001153 //Actually we only need to go half way round to verify full mesh connectivity
1154 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001155 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001156 for (Interface dstInterface : interfaces.values()) {
1157 for (Interface srcInterface : interfaces.values()) {
1158 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001159 continue;
1160 }
1161
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001162 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001163 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001164
1165 if (shortestPath == null){
1166 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001167 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001168 return;
1169 }
1170 }
1171 }
1172 topologyReady = true;
1173 }
1174
1175 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001176 if (!switchesConnected){
1177 checkSwitchesConnected();
1178 }
1179 boolean oldTopologyReadyStatus = topologyReady;
1180 if (switchesConnected && !topologyReady){
1181 checkTopologyReady();
1182 }
1183 if (!oldTopologyReadyStatus && topologyReady){
1184 beginRouting();
1185 }
1186 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001187
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001188 private void doUpdatesThread() {
1189 boolean interrupted = false;
1190 try {
1191 while (true) {
1192 try {
1193 RibUpdate update = ribUpdates.take();
1194 switch (update.getOperation()){
1195 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001196 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001197 break;
1198 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001199 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001200 break;
1201 }
1202 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001203 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001204 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001205 } catch (Exception e) {
1206 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001207 }
1208 }
1209 } finally {
1210 if (interrupted) {
1211 Thread.currentThread().interrupt();
1212 }
1213 }
1214 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001215
1216 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001217 public void topologyChanged() {
1218 if (topologyReady) {
1219 return;
1220 }
1221
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001222 boolean refreshNeeded = false;
1223 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1224 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1225 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001226 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001227 refreshNeeded = true;
1228 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001229
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001230 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001231
Jonathan Hart98957bf2013-07-01 14:49:24 +12001232 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1233 synchronized (linkUpdates) {
1234 linkUpdates.add(ldu);
1235 }
1236 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001237 }
1238
Jonathan Hart64c0b202013-08-20 15:45:07 +12001239 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001240 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001241 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001242 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001243
1244 @Override
1245 public void addedSwitch(IOFSwitch sw) {
1246 if (!topologyReady) {
1247 sw.clearAllFlowMods();
1248 }
1249 }
1250
1251 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001252 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001253
1254 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001255 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001256
1257 @Override
1258 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001259 return "BgpRoute";
1260 }
1261
1262 /*
1263 * ILayer3InfoService methods
1264 */
1265
1266 @Override
1267 public boolean isInterfaceAddress(InetAddress address) {
1268 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1269 return (intf != null && intf.getIpAddress().equals(address));
1270 }
1271
1272 @Override
1273 public boolean inConnectedNetwork(InetAddress address) {
1274 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1275 return (intf != null && !intf.getIpAddress().equals(address));
1276 }
1277
1278 @Override
1279 public boolean fromExternalNetwork(long inDpid, short inPort) {
1280 for (Interface intf : interfaces.values()) {
1281 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1282 return true;
1283 }
1284 }
1285 return false;
1286 }
1287
1288 @Override
1289 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1290 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1291 }
1292
1293 @Override
1294 public boolean hasLayer3Configuration() {
1295 return !interfaces.isEmpty();
1296 }
1297
1298 @Override
1299 public MACAddress getRouterMacAddress() {
1300 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001301 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001302}