blob: a698fd549839abbadfd3beba72bfc8a838b4823c [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;
60import org.openflow.protocol.OFMessage;
61import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120062import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070063import org.openflow.protocol.OFType;
64import org.openflow.protocol.action.OFAction;
65import org.openflow.protocol.action.OFActionDataLayerDestination;
66import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120067import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080068import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
Jonathan Hart4dfc3652013-08-02 20:22:36 +120071import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120072import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120073import com.google.common.collect.Multimaps;
74import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120075import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120076import com.google.common.util.concurrent.ThreadFactoryBuilder;
77
Jonathan Hart1236a9b2013-06-18 22:10:05 +120078public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120079 ITopologyListener, IArpRequester,
Jonathan Hart5afde492013-10-01 12:30:53 +130080 IOFSwitchListener, ILayer3InfoService,
81 IProxyArpService {
pingping-lina2cbfad2013-03-07 08:39:21 +080082
83 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
84
85 protected IFloodlightProviderService floodlightProvider;
86 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070087 protected ITopoRouteService topoRouteService;
Jonathan Harte7694532013-09-12 12:34:46 +120088 protected ILinkDiscoveryService linkDiscoveryService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070089 protected IRestApiService restApi;
90
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120091 protected ProxyArpManager proxyArp;
92
Jonathan Hart29b972d2013-08-12 23:43:51 +120093 protected IPatriciaTrie<RibEntry> ptree;
Jonathan Hartabf10222013-08-13 10:19:34 +120094 protected IPatriciaTrie<Interface> interfacePtrie;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120095 protected BlockingQueue<RibUpdate> ribUpdates;
96
Jonathan Hart61ba9372013-05-19 20:10:29 -070097 protected String bgpdRestIp;
98 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120099 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700100
101 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
102 //the controller/OS should hand out cookie IDs to prevent conflicts.
103 protected final long APP_COOKIE = 0xa0000000000000L;
104 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
105 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
106 //Cookie for flows in ingress switches that rewrite the MAC address
107 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200108 //Cookie for flows that setup BGP paths
109 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200110 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
111 //need to be higher priority than this otherwise the rewrite may not get done
112 protected final short SDNIP_PRIORITY = 10;
Jonathan Hartc82051c2013-08-24 15:12:20 +1200113 protected final short ARP_PRIORITY = 20;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700114
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200115 protected final short BGP_PORT = 179;
116
Jonathan Hart98957bf2013-07-01 14:49:24 +1200117 protected final int TOPO_DETECTION_WAIT = 2; //seconds
118
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200119 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200120 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200121 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200122 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200123 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart2f790d22013-08-15 14:01:24 +1200124 protected MACAddress bgpdMacAddress;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200125
126 //True when all switches have connected
127 protected volatile boolean switchesConnected = false;
128 //True when we have a full mesh of shortest paths between gateways
129 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200130
Jonathan Hart98957bf2013-07-01 14:49:24 +1200131 protected ArrayList<LDUpdate> linkUpdates;
132 protected SingletonTask topologyChangeDetectorTask;
133
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200134 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200135
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200136 protected Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200137
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200138 protected ExecutorService bgpUpdatesExecutor;
139
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200140 protected Map<InetAddress, Path> pushedPaths;
141 protected Map<Prefix, Path> prefixToPath;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200142 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200143
144 protected volatile Map<Long, ?> topoRouteTopology = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200145
Jonathan Hart98957bf2013-07-01 14:49:24 +1200146 protected class TopologyChangeDetector implements Runnable {
147 @Override
148 public void run() {
149 log.debug("Running topology change detection task");
150 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200151 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200152 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
153
154 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200155
156 Iterator<LDUpdate> it = linkUpdates.iterator();
157 while (it.hasNext()){
158 LDUpdate ldu = it.next();
159 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
160 ldu.getDst(), ldu.getDstPort());
161
162 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200163 it.remove();
164 }
165 }
166 }
167
Jonathan Hart64c0b202013-08-20 15:45:07 +1200168 if (!topologyReady) {
169 if (linkUpdates.isEmpty()){
170 //All updates have been seen in network map.
171 //We can check if topology is ready
172 log.debug("No known changes outstanding. Checking topology now");
173 checkStatus();
174 }
175 else {
176 //We know of some link updates that haven't propagated to the database yet
177 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
178 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
179 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200180 }
181 }
182 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700183
Jonathan Hartd1f23252013-06-13 15:17:05 +1200184 private void readGatewaysConfiguration(String gatewaysFilename){
185 File gatewaysFile = new File(gatewaysFilename);
186 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700187
Jonathan Hartd1f23252013-06-13 15:17:05 +1200188 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200189 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
190
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200191 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200192 interfaces = new HashMap<String, Interface>();
193 for (Interface intf : config.getInterfaces()){
194 interfaces.put(intf.getName(), intf);
195 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200196 bgpPeers = new HashMap<InetAddress, BgpPeer>();
197 for (BgpPeer peer : config.getPeers()){
198 bgpPeers.put(peer.getIpAddress(), peer);
199 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200200
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200201 bgpdAttachmentPoint = new SwitchPort(
202 new Dpid(config.getBgpdAttachmentDpid()),
203 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200204
Jonathan Hart2f790d22013-08-15 14:01:24 +1200205 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200206 } catch (JsonParseException e) {
207 log.error("Error in JSON file", e);
208 System.exit(1);
209 } catch (JsonMappingException e) {
210 log.error("Error in JSON file", e);
211 System.exit(1);
212 } catch (IOException e) {
213 log.error("Error reading JSON file", e);
214 System.exit(1);
215 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200216
217 //Populate the interface Patricia Trie
218 for (Interface intf : interfaces.values()) {
219 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
220 interfacePtrie.put(prefix, intf);
221 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700222 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800223
224 @Override
225 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700226 Collection<Class<? extends IFloodlightService>> l
227 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800228 l.add(IBgpRouteService.class);
229 return l;
230 }
231
232 @Override
233 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700234 Map<Class<? extends IFloodlightService>, IFloodlightService> m
235 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800236 m.put(IBgpRouteService.class, this);
Jonathan Hart5afde492013-10-01 12:30:53 +1300237 m.put(IProxyArpService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800238 return m;
239 }
240
pingping-lina2cbfad2013-03-07 08:39:21 +0800241 @Override
242 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700243 Collection<Class<? extends IFloodlightService>> l
244 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800245 l.add(IFloodlightProviderService.class);
246 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700247 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800248 return l;
249 }
250
251 @Override
252 public void init(FloodlightModuleContext context)
253 throws FloodlightModuleException {
254
Jonathan Hart29b972d2013-08-12 23:43:51 +1200255 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200256 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200257
258 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200259
pingping-lina2cbfad2013-03-07 08:39:21 +0800260 // Register floodlight provider and REST handler.
261 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800262 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200263 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200264 restApi = context.getServiceImpl(IRestApiService.class);
265
266 //TODO We'll initialise this here for now, but it should really be done as
267 //part of the controller core
Jonathan Hart5afde492013-10-01 12:30:53 +1300268 proxyArp = new ProxyArpManager(floodlightProvider, topology, this, restApi);
pingping-lina2cbfad2013-03-07 08:39:21 +0800269
Jonathan Hart98957bf2013-07-01 14:49:24 +1200270 linkUpdates = new ArrayList<LDUpdate>();
271 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
272 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700273
274 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200275
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200276 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200277 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
278 HashMultimap.<InetAddress, RibUpdate>create());
279
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200280 pushedPaths = new HashMap<InetAddress, Path>();
281 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200282 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
283
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200284 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
285 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
286
Jonathan Hart61ba9372013-05-19 20:10:29 -0700287 //Read in config values
288 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
289 if (bgpdRestIp == null){
290 log.error("BgpdRestIp property not found in config file");
291 System.exit(1);
292 }
293 else {
294 log.info("BgpdRestIp set to {}", bgpdRestIp);
295 }
296
297 routerId = context.getConfigParams(this).get("RouterId");
298 if (routerId == null){
299 log.error("RouterId property not found in config file");
300 System.exit(1);
301 }
302 else {
303 log.info("RouterId set to {}", routerId);
304 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200305
Jonathan Hart9575cb62013-07-05 13:43:49 +1200306 String configFilenameParameter = context.getConfigParams(this).get("configfile");
307 if (configFilenameParameter != null){
308 configFilename = configFilenameParameter;
309 }
310 log.debug("Config file set to {}", configFilename);
311
312 readGatewaysConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200313 }
314
315 @Override
316 public void startUp(FloodlightModuleContext context) {
317 restApi.addRestletRoutable(new BgpRouteWebRoutable());
318 topology.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200319 floodlightProvider.addOFSwitchListener(this);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200320
Jonathan Hart2f790d22013-08-15 14:01:24 +1200321 proxyArp.startUp();
322
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200323 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
324
325 //Retrieve the RIB from BGPd during startup
326 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800327 }
328
Jonathan Hart29b972d2013-08-12 23:43:51 +1200329 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800330 return ptree;
331 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700332
333 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200334 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800335 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700336
pingping-line2a09ca2013-03-23 09:33:58 +0800337 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700338 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800339 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700340
pingping-line2a09ca2013-03-23 09:33:58 +0800341 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700342 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800343 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800344
Jonathan Hart61ba9372013-05-19 20:10:29 -0700345 private void retrieveRib(){
346 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
347 String response = RestClient.get(url);
348
349 if (response.equals("")){
350 return;
351 }
352
353 response = response.replaceAll("\"", "'");
354 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
355 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
356 String router_id = jsonObj.getString("router-id");
357
358 int size = rib_json_array.size();
359
360 log.info("Retrived RIB of {} entries from BGPd", size);
361
362 for (int j = 0; j < size; j++) {
363 JSONObject second_json_object = rib_json_array.getJSONObject(j);
364 String prefix = second_json_object.getString("prefix");
365 String nexthop = second_json_object.getString("nexthop");
366
367 //insert each rib entry into the local rib;
368 String[] substring = prefix.split("/");
369 String prefix1 = substring[0];
370 String mask1 = substring[1];
371
372 Prefix p;
373 try {
374 p = new Prefix(prefix1, Integer.valueOf(mask1));
375 } catch (NumberFormatException e) {
376 log.warn("Wrong mask format in RIB JSON: {}", mask1);
377 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200378 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700379 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
380 continue;
381 }
382
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200383 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200384
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200385 try {
386 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
387 } catch (InterruptedException e) {
388 log.debug("Interrupted while pushing onto update queue");
389 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700390 }
391 }
392
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200393 @Override
394 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200395 try {
396 ribUpdates.put(update);
397 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200398 log.debug("Interrupted while putting on ribUpdates queue", e);
399 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200400 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200401 }
402
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200403 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200404 Prefix prefix = update.getPrefix();
405
Jonathan Hart9ea31212013-08-12 21:40:34 +1200406 log.debug("Processing prefix add {}", prefix);
407
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200408 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200409
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200410 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200411 //There was an existing nexthop for this prefix. This update supersedes that,
412 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200413 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200414 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200415
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200416 if (update.getRibEntry().getNextHop().equals(
417 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200418 //Route originated by SDN domain
419 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200420 log.debug("Own route {} to {}", prefix,
421 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200422 return;
423 }
424
425 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200426 }
427
Jonathan Hart309889c2013-08-13 23:26:24 +1200428 private void _processRibAdd(RibUpdate update) {
429 Prefix prefix = update.getPrefix();
430 RibEntry rib = update.getRibEntry();
431
432 InetAddress dstIpAddress = rib.getNextHop();
433
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200434 //See if we know the MAC address of the next hop
Jonathan Hartabad6a52013-09-30 18:17:21 +1300435 MACAddress nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200436
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200437 //Find the attachment point (egress interface) of the next hop
438 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200439 if (bgpPeers.containsKey(dstIpAddress)) {
440 //Route to a peer
441 log.debug("Route to peer {}", dstIpAddress);
442 BgpPeer peer = bgpPeers.get(dstIpAddress);
443 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200444 }
445 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200446 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200447 log.debug("Route to non-peer {}", dstIpAddress);
448 egressInterface = interfacePtrie.match(
449 new Prefix(dstIpAddress.getAddress(), 32));
450 if (egressInterface == null) {
451 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
452 return;
453 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200454 }
455
456 if (nextHopMacAddress == null) {
457 prefixesWaitingOnArp.put(dstIpAddress,
458 new RibUpdate(Operation.UPDATE, prefix, rib));
459 proxyArp.sendArpRequest(dstIpAddress, this, true);
460 return;
461 }
462 else {
463 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200464 //If the prefix is for a non-peer we need to ensure there's a path,
465 //and push one if there isn't.
466 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200467 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200468 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300469 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200470 pushedPaths.put(dstIpAddress, path);
471 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200472
473 path.incrementUsers();
474 prefixToPath.put(prefix, path);
475 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200476
477 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200478 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
479 }
480 }
481
Jonathan Hartabad6a52013-09-30 18:17:21 +1300482 private void addPrefixFlows(Prefix prefix, Interface egressInterface, MACAddress nextHopMacAddress) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200483 log.debug("Adding flows for prefix {} added, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300484 prefix, nextHopMacAddress);
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200485
486 //We only need one flow mod per switch, so pick one interface on each switch
487 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
488 for (Interface intf : interfaces.values()) {
489 if (!srcInterfaces.containsKey(intf.getDpid())
490 && intf != egressInterface) {
491 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200492 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200493 }
494
495 //Add a flow to rewrite mac for this prefix to all other border switches
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200496 for (Interface srcInterface : srcInterfaces.values()) {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200497 DataPath shortestPath;
498 if (topoRouteTopology == null) {
499 shortestPath = topoRouteService.getShortestPath(
500 srcInterface.getSwitchPort(),
501 egressInterface.getSwitchPort());
502 }
503 else {
504 shortestPath = topoRouteService.getTopoShortestPath(
505 topoRouteTopology, srcInterface.getSwitchPort(),
506 egressInterface.getSwitchPort());
507 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200508
509 if (shortestPath == null){
510 log.debug("Shortest path between {} and {} not found",
511 srcInterface.getSwitchPort(),
512 egressInterface.getSwitchPort());
513 return; // just quit here?
514 }
515
516 //Set up the flow mod
517 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
518 .getMessage(OFType.FLOW_MOD);
519
520 fm.setIdleTimeout((short)0)
521 .setHardTimeout((short)0)
522 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
523 .setCookie(MAC_RW_COOKIE)
524 .setCommand(OFFlowMod.OFPFC_ADD)
525 .setPriority(SDNIP_PRIORITY)
526 .setLengthU(OFFlowMod.MINIMUM_LENGTH
527 + OFActionDataLayerDestination.MINIMUM_LENGTH
528 + OFActionOutput.MINIMUM_LENGTH);
529
530 OFMatch match = new OFMatch();
531 match.setDataLayerType(Ethernet.TYPE_IPv4);
532 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
533
534 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
535 fm.setMatch(match);
536
537 //Set up MAC rewrite action
538 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartabad6a52013-09-30 18:17:21 +1300539 macRewriteAction.setDataLayerAddress(nextHopMacAddress.toBytes());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200540
541 //Set up output action
542 OFActionOutput outputAction = new OFActionOutput();
543 outputAction.setMaxLength((short)0xffff);
544 Port outputPort = shortestPath.flowEntries().get(0).outPort();
545 outputAction.setPort(outputPort.value());
546
547 List<OFAction> actions = new ArrayList<OFAction>();
548 actions.add(macRewriteAction);
549 actions.add(outputAction);
550 fm.setActions(actions);
551
552 //Write to switch
553 IOFSwitch sw = floodlightProvider.getSwitches()
554 .get(srcInterface.getDpid());
555
556 if (sw == null){
557 log.warn("Switch not found when pushing flow mod");
558 continue;
559 }
560
561 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
562
563 List<OFMessage> msglist = new ArrayList<OFMessage>();
564 msglist.add(fm);
565 try {
566 sw.write(msglist, null);
567 sw.flush();
Jonathan Hart08ee8522013-09-22 17:34:43 +1200568
569 /*
570 * XXX Rate limit hack!
571 * This should be solved properly by adding a rate limiting
572 * layer on top of the switches if we know they need it.
573 */
Jonathan Hart9971e1c2013-09-17 10:47:40 +1200574 Thread.sleep(1);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200575 } catch (IOException e) {
576 log.error("Failure writing flow mod", e);
Jonathan Hart65139e42013-09-13 16:52:25 +1200577 } catch (InterruptedException e) {
578 // TODO handle this properly
579 log.error("Interrupted", e);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200580 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200581 }
582 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200583
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200584 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200585 Prefix prefix = update.getPrefix();
586
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200587 if (ptree.remove(prefix, update.getRibEntry())) {
588 /*
589 * Only delete flows if an entry was actually removed from the trie.
590 * If no entry was removed, the <prefix, nexthop> wasn't there so
591 * it's probably already been removed and we don't need to do anything
592 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200593 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200594 }
595 }
596
597 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
598 deletePrefixFlows(prefix);
599
600 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200601
Jonathan Hart309889c2013-08-13 23:26:24 +1200602 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
603 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200604 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200605
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200606 if (path != null) {
607 //path could be null if we added to the Ptree but didn't push
608 //flows yet because we were waiting to resolve ARP
Jonathan Hart309889c2013-08-13 23:26:24 +1200609
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200610 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200611 if (path.getUsers() <= 0 && !path.isPermanent()) {
612 deletePath(path);
613 pushedPaths.remove(path.getDstIpAddress());
614 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200615 }
616 }
617 }
618
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200619 private void deletePrefixFlows(Prefix prefix) {
620 log.debug("Deleting flows for prefix {}", prefix);
621
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200622 Collection<PushedFlowMod> pushedFlowMods
623 = pushedFlows.removeAll(prefix);
624
625 for (PushedFlowMod pfm : pushedFlowMods) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200626 if (log.isTraceEnabled()) {
627 log.trace("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
628 new Object[] {HexString.toHexString(pfm.getDpid()),
629 pfm.getFlowMod().getMatch().getNetworkDestination() +
630 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
631 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
632 .getDataLayerAddress())});
633 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200634
635 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
636 }
637 }
638
639 private void deletePath(Path path) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200640 log.debug("Deleting flows for path to {}",
641 path.getDstIpAddress().getHostAddress());
642
Jonathan Hart309889c2013-08-13 23:26:24 +1200643 for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200644 if (log.isTraceEnabled()) {
645 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
646 new Object[] {HexString.toHexString(pfm.getDpid()),
647 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
648 });
649 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200650
651 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
652 }
653 }
654
655 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
656 addFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
657 .setOutPort(OFPort.OFPP_NONE)
658 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
659
660 addFlowMod.getActions().clear();
661
662 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
663 if (sw == null) {
664 log.warn("Switch not found when pushing delete flow mod");
665 return;
666 }
667
668 try {
669 sw.write(addFlowMod, null);
670 sw.flush();
671 } catch (IOException e) {
672 log.error("Failure writing flow mod", e);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200673 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200674 }
675
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200676 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200677 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200678
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700679 /*
680 * On startup we need to calculate a full mesh of paths between all gateway
681 * switches
682 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200683 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700684 //For each border router, calculate and install a path from every other
685 //border switch to said border router. However, don't install the entry
686 //in to the first hop switch, as we need to install an entry to rewrite
687 //for each prefix received. This will be done later when prefixes have
688 //actually been received.
689
Jonathan Hartc824ad02013-07-03 15:58:45 +1200690 for (BgpPeer peer : bgpPeers.values()) {
691 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200692
Jonathan Hart309889c2013-08-13 23:26:24 +1200693 //We know there's not already a Path here pushed, because this is
694 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200695 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200696 path.setPermanent();
697
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200698 //See if we know the MAC address of the peer. If not we can't
699 //do anything until we learn it
Jonathan Hartabad6a52013-09-30 18:17:21 +1300700 MACAddress macAddress = proxyArp.getMacAddress(peer.getIpAddress());
701 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200702 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
703 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200704 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700705
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200706 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
707 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700708 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200709
710 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300711 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700712 }
713 }
714
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200715 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200716 Interface dstInterface = path.getDstInterface();
717
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200718 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
719 dstMacAddress);
720
Jonathan Hart309889c2013-08-13 23:26:24 +1200721 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
722
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200723 for (Interface srcInterface : interfaces.values()) {
724 if (dstInterface.equals(srcInterface.getName())){
725 continue;
726 }
727
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200728 DataPath shortestPath;
729 if (topoRouteTopology == null) {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200730 shortestPath = topoRouteService.getShortestPath(
731 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
732 }
733 else {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200734 shortestPath = topoRouteService.getTopoShortestPath(topoRouteTopology,
735 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
736 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200737
738 if (shortestPath == null){
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200739 log.warn("Shortest path between {} and {} not found",
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200740 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200741 return;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200742 }
743
Jonathan Hart309889c2013-08-13 23:26:24 +1200744 pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200745 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200746
747 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200748 }
749
Jonathan Hart309889c2013-08-13 23:26:24 +1200750 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
751 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
752
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700753 //Set up the flow mod
754 OFFlowMod fm =
755 (OFFlowMod) floodlightProvider.getOFMessageFactory()
756 .getMessage(OFType.FLOW_MOD);
757
758 OFActionOutput action = new OFActionOutput();
759 action.setMaxLength((short)0xffff);
760 List<OFAction> actions = new ArrayList<OFAction>();
761 actions.add(action);
762
763 fm.setIdleTimeout((short)0)
764 .setHardTimeout((short)0)
765 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
766 .setCookie(L2_FWD_COOKIE)
767 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hartbdc87462013-09-24 15:03:23 +1200768 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700769 .setActions(actions)
770 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
771
772 //Don't push the first flow entry. We need to push entries in the
773 //first switch based on IP prefix which we don't know yet.
774 for (int i = 1; i < flowEntries.size(); i++){
775 FlowEntry flowEntry = flowEntries.get(i);
776
777 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200778 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700779 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
780 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
781
782 fm.setMatch(match);
783
784 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
785
786 if (sw == null){
787 log.warn("Switch not found when pushing flow mod");
788 continue;
789 }
790
Jonathan Hart309889c2013-08-13 23:26:24 +1200791 flowMods.add(new PushedFlowMod(sw.getId(), fm));
792
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700793 List<OFMessage> msglist = new ArrayList<OFMessage>();
794 msglist.add(fm);
795 try {
796 sw.write(msglist, null);
797 sw.flush();
798 } catch (IOException e) {
799 log.error("Failure writing flow mod", e);
800 }
801
802 try {
803 fm = fm.clone();
804 } catch (CloneNotSupportedException e1) {
805 log.error("Failure cloning flow mod", e1);
806 }
807 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200808
809 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700810 }
811
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200812 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200813 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200814 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
815
816 DataPath path = topoRouteService.getShortestPath(
817 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
818
819 if (path == null){
820 log.debug("Unable to compute path for BGP traffic for {}",
821 bgpPeer.getIpAddress());
822 continue;
823 }
824
825 //Set up the flow mod
826 OFFlowMod fm =
827 (OFFlowMod) floodlightProvider.getOFMessageFactory()
828 .getMessage(OFType.FLOW_MOD);
829
830 OFActionOutput action = new OFActionOutput();
831 action.setMaxLength((short)0xffff);
832 List<OFAction> actions = new ArrayList<OFAction>();
833 actions.add(action);
834
835 fm.setIdleTimeout((short)0)
836 .setHardTimeout((short)0)
837 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
838 .setCookie(BGP_COOKIE)
839 .setCommand(OFFlowMod.OFPFC_ADD)
840 .setPriority(SDNIP_PRIORITY)
841 .setActions(actions)
842 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
843
844 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
845 OFMatch forwardMatchSrc = new OFMatch();
846
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200847 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
848 + "/32";
849 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
850 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200851
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200852 //Common match fields
853 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200854 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
855 forwardMatchSrc.setTransportDestination(BGP_PORT);
856 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
857 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
858
859
860 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
861
862 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
863 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
864
865 OFMatch forwardMatchDst = forwardMatchSrc.clone();
866
867 forwardMatchSrc.setTransportSource(BGP_PORT);
868 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
869 forwardMatchDst.setTransportDestination(BGP_PORT);
870 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
871
872 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
873 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
874
875 OFMatch reverseMatchDst = reverseMatchSrc.clone();
876
877 reverseMatchSrc.setTransportSource(BGP_PORT);
878 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
879 reverseMatchDst.setTransportDestination(BGP_PORT);
880 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
881
882 fm.setMatch(forwardMatchSrc);
883
Jonathan Hart38c84932013-08-10 17:49:27 +1200884 OFMatch forwardIcmpMatch = new OFMatch();
885 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
886 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
887 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
888 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
889
890 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
891 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
892 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
893
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200894 for (FlowEntry flowEntry : path.flowEntries()){
895 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
896 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200897 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200898 try {
899 forwardFlowModSrc = fm.clone();
900 forwardFlowModDst = fm.clone();
901 reverseFlowModSrc = fm.clone();
902 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200903 forwardIcmp = fm.clone();
904 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200905 } catch (CloneNotSupportedException e) {
906 log.warn("Clone failed", e);
907 continue;
908 }
909
910 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
911 forwardFlowModSrc.setMatch(forwardMatchSrc);
912 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
913 .setPort(flowEntry.outPort().value());
914
915 forwardMatchDst.setInputPort(flowEntry.inPort().value());
916 forwardFlowModDst.setMatch(forwardMatchDst);
917 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
918 .setPort(flowEntry.outPort().value());
919
920 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
921 reverseFlowModSrc.setMatch(reverseMatchSrc);
922 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
923 .setPort(flowEntry.inPort().value());
924
925 reverseMatchDst.setInputPort(flowEntry.outPort().value());
926 reverseFlowModDst.setMatch(reverseMatchDst);
927 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
928 .setPort(flowEntry.inPort().value());
929
Jonathan Hart38c84932013-08-10 17:49:27 +1200930 ((OFActionOutput)forwardIcmp.getActions().get(0))
931 .setPort(flowEntry.outPort().value());
932 forwardIcmp.setMatch(forwardIcmpMatch);
933
934 ((OFActionOutput)reverseIcmp.getActions().get(0))
935 .setPort(flowEntry.inPort().value());
936 reverseIcmp.setMatch(reverseIcmpMatch);
937
938
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200939 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
940
Jonathan Hart38c84932013-08-10 17:49:27 +1200941 if (sw == null) {
942 log.warn("Switch not found when pushing BGP paths");
943 return;
944 }
945
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200946 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
947 msgList.add(forwardFlowModSrc);
948 msgList.add(forwardFlowModDst);
949 msgList.add(reverseFlowModSrc);
950 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +1200951 msgList.add(forwardIcmp);
952 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200953
954 try {
955 sw.write(msgList, null);
956 sw.flush();
957 } catch (IOException e) {
958 log.error("Failure writing flow mod", e);
959 }
960 }
961 }
962 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200963
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200964 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +1300965 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
966 log.debug("Received ARP response: {} => {}",
967 ipAddress.getHostAddress(), macAddress);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200968
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200969 /*
970 * We synchronize on this to prevent changes to the ptree while we're pushing
971 * flows to the switches. If the ptree changes, the ptree and switches
972 * could get out of sync.
973 */
974 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200975 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200976
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200977 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200978 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300979 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200980 path.getDstInterface().getSwitchPort()});
981 //These paths should always be to BGP peers. Paths to non-peers are
982 //handled once the first prefix is ready to push
983 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200984 //A path already got pushed to this endpoint while we were waiting
985 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200986 if (path.isPermanent()) {
987 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200988 }
989 }
990 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300991 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200992 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200993 }
994 }
995
Jonathan Hart309889c2013-08-13 23:26:24 +1200996 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
997
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200998 for (RibUpdate update : prefixesToPush) {
999 //These will always be adds
1000
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001001 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001002 if (rib != null && rib.equals(update.getRibEntry())) {
1003 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001004 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001005 //We only push prefix flows if the prefix is still in the ptree
1006 //and the next hop is the same as our update. The prefix could
1007 //have been removed while we were waiting for the ARP, or the
1008 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +12001009 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001010 } else {
1011 log.debug("Received ARP response, but {},{} is no longer in ptree",
1012 update.getPrefix(), update.getRibEntry());
1013 }
1014 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001015 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001016 }
1017
Jonathan Hartc82051c2013-08-24 15:12:20 +12001018 private void setupArpFlows() {
1019 OFMatch match = new OFMatch();
1020 match.setDataLayerType(Ethernet.TYPE_ARP);
1021 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1022
1023 OFFlowMod fm = new OFFlowMod();
1024 fm.setMatch(match);
1025
1026 OFActionOutput action = new OFActionOutput();
1027 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1028 action.setMaxLength((short)0xffff);
1029 List<OFAction> actions = new ArrayList<OFAction>(1);
1030 actions.add(action);
1031 fm.setActions(actions);
1032
1033 fm.setIdleTimeout((short)0)
1034 .setHardTimeout((short)0)
1035 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1036 .setCookie(0)
1037 .setCommand(OFFlowMod.OFPFC_ADD)
1038 .setPriority(ARP_PRIORITY)
1039 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1040
1041 for (String strdpid : switches){
1042 IOFSwitch sw = floodlightProvider.getSwitches().get(HexString.toLong(strdpid));
1043 if (sw == null) {
1044 log.debug("Couldn't find switch to push ARP flow");
1045 }
1046 else {
1047 try {
1048 sw.write(fm, null);
1049 } catch (IOException e) {
1050 log.warn("Failure writing ARP flow to switch", e);
1051 }
1052 }
1053 }
1054 }
1055
Jonathan Hartf886fa12013-09-18 14:46:29 +12001056 private void setupDefaultDropFlows() {
1057 OFFlowMod fm = new OFFlowMod();
1058 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001059 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Jonathan Hartf886fa12013-09-18 14:46:29 +12001060
1061 fm.setIdleTimeout((short)0)
1062 .setHardTimeout((short)0)
1063 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1064 .setCookie(0)
1065 .setCommand(OFFlowMod.OFPFC_ADD)
1066 .setPriority((short)0)
1067 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
1068
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001069 OFFlowMod fmLLDP;
1070 OFFlowMod fmBDDP;
1071 try {
1072 fmLLDP = fm.clone();
1073 fmBDDP = fm.clone();
1074 } catch (CloneNotSupportedException e1) {
1075 log.error("Error cloning flow mod", e1);
1076 return;
1077 }
1078
1079 OFMatch matchLLDP = new OFMatch();
1080 matchLLDP.setDataLayerType((short)0x8942);
1081 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1082 fmLLDP.setMatch(matchLLDP);
1083
1084 OFMatch matchBDDP = new OFMatch();
1085 matchBDDP.setDataLayerType((short)0x88cc);
1086 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1087 fmBDDP.setMatch(matchBDDP);
1088
1089 OFActionOutput action = new OFActionOutput();
1090 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1091 action.setMaxLength((short)0xffff);
1092 List<OFAction> actions = new ArrayList<OFAction>(1);
1093 actions.add(action);
1094
1095 fmLLDP.setActions(actions);
1096 fmBDDP.setActions(actions);
1097
1098 fmLLDP.setPriority(ARP_PRIORITY);
1099 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1100 fmBDDP.setPriority(ARP_PRIORITY);
1101 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1102
Jonathan Hartf886fa12013-09-18 14:46:29 +12001103 for (String strdpid : switches){
1104 IOFSwitch sw = floodlightProvider.getSwitches().get(HexString.toLong(strdpid));
1105 if (sw == null) {
1106 log.debug("Couldn't find switch to push default deny flow");
1107 }
1108 else {
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001109 List<OFMessage> msgList = new ArrayList<OFMessage>();
1110 msgList.add(fm);
1111 msgList.add(fmLLDP);
1112 msgList.add(fmBDDP);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001113 try {
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001114 sw.write(msgList, null);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001115 } catch (IOException e) {
1116 log.warn("Failure writing default deny flow to switch", e);
1117 }
1118 }
1119 }
1120 }
1121
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001122 private void beginRouting(){
1123 log.debug("Topology is now ready, beginning routing function");
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001124 topoRouteTopology = topoRouteService.prepareShortestPathTopo();
1125
Jonathan Hartc82051c2013-08-24 15:12:20 +12001126 setupArpFlows();
Jonathan Hartf886fa12013-09-18 14:46:29 +12001127 setupDefaultDropFlows();
Jonathan Hartc82051c2013-08-24 15:12:20 +12001128
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001129 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001130 setupFullMesh();
Jonathan Harte7694532013-09-12 12:34:46 +12001131
1132 //Suppress link discovery on external-facing router ports
1133 for (Interface intf : interfaces.values()) {
1134 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1135 }
1136
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001137 bgpUpdatesExecutor.execute(new Runnable() {
1138 @Override
1139 public void run() {
1140 doUpdatesThread();
1141 }
1142 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001143 }
1144
1145 private void checkSwitchesConnected(){
1146 for (String dpid : switches){
1147 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1148 log.debug("Not all switches are here yet");
1149 return;
1150 }
1151 }
1152 switchesConnected = true;
1153 }
1154
Jonathan Hartc824ad02013-07-03 15:58:45 +12001155 //Actually we only need to go half way round to verify full mesh connectivity
1156 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001157 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001158 for (Interface dstInterface : interfaces.values()) {
1159 for (Interface srcInterface : interfaces.values()) {
1160 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001161 continue;
1162 }
1163
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001164 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001165 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001166
1167 if (shortestPath == null){
1168 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001169 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001170 return;
1171 }
1172 }
1173 }
1174 topologyReady = true;
1175 }
1176
1177 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001178 if (!switchesConnected){
1179 checkSwitchesConnected();
1180 }
1181 boolean oldTopologyReadyStatus = topologyReady;
1182 if (switchesConnected && !topologyReady){
1183 checkTopologyReady();
1184 }
1185 if (!oldTopologyReadyStatus && topologyReady){
1186 beginRouting();
1187 }
1188 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001189
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001190 private void doUpdatesThread() {
1191 boolean interrupted = false;
1192 try {
1193 while (true) {
1194 try {
1195 RibUpdate update = ribUpdates.take();
1196 switch (update.getOperation()){
1197 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001198 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001199 break;
1200 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001201 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001202 break;
1203 }
1204 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001205 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001206 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001207 } catch (Exception e) {
1208 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001209 }
1210 }
1211 } finally {
1212 if (interrupted) {
1213 Thread.currentThread().interrupt();
1214 }
1215 }
1216 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001217
1218 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001219 public void topologyChanged() {
1220 if (topologyReady) {
1221 return;
1222 }
1223
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001224 boolean refreshNeeded = false;
1225 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1226 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1227 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001228 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001229 refreshNeeded = true;
1230 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001231
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001232 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001233
Jonathan Hart98957bf2013-07-01 14:49:24 +12001234 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1235 synchronized (linkUpdates) {
1236 linkUpdates.add(ldu);
1237 }
1238 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001239 }
1240
Jonathan Hart64c0b202013-08-20 15:45:07 +12001241 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001242 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001243 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001244 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001245
1246 @Override
1247 public void addedSwitch(IOFSwitch sw) {
1248 if (!topologyReady) {
1249 sw.clearAllFlowMods();
1250 }
1251 }
1252
1253 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001254 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001255
1256 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001257 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001258
1259 @Override
1260 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001261 return "BgpRoute";
1262 }
1263
1264 /*
1265 * ILayer3InfoService methods
1266 */
1267
1268 @Override
1269 public boolean isInterfaceAddress(InetAddress address) {
1270 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1271 return (intf != null && intf.getIpAddress().equals(address));
1272 }
1273
1274 @Override
1275 public boolean inConnectedNetwork(InetAddress address) {
1276 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1277 return (intf != null && !intf.getIpAddress().equals(address));
1278 }
1279
1280 @Override
1281 public boolean fromExternalNetwork(long inDpid, short inPort) {
1282 for (Interface intf : interfaces.values()) {
1283 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1284 return true;
1285 }
1286 }
1287 return false;
1288 }
1289
1290 @Override
1291 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1292 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1293 }
1294
1295 @Override
1296 public boolean hasLayer3Configuration() {
1297 return !interfaces.isEmpty();
1298 }
1299
1300 @Override
1301 public MACAddress getRouterMacAddress() {
1302 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001303 }
Jonathan Hart5afde492013-10-01 12:30:53 +13001304
1305 /*
1306 * TODO This is a hack to get the REST API to work for ProxyArpManager.
1307 * The REST API is currently tied to the Floodlight module system and we
1308 * need to separate it to allow ONOS modules to use it. For now we will
1309 * proxy calls through to the ProxyArpManager (which is not a Floodlight
1310 * module) through this class which is a module.
1311 */
1312 @Override
1313 public MACAddress getMacAddress(InetAddress ipAddress) {
1314 return proxyArp.getMacAddress(ipAddress);
1315 }
1316
1317 @Override
1318 public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
1319 boolean retry) {
1320 proxyArp.sendArpRequest(ipAddress, requester, retry);
1321 }
1322
1323 @Override
1324 public List<String> getMappings() {
1325 return proxyArp.getMappings();
1326 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001327}