blob: 14ecf850d445ac96a27481ad4783dfe17ec27943 [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;
Jonathan Hart98957bf2013-07-01 14:49:24 +120037import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070038import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
39import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harte7694532013-09-12 12:34:46 +120040import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120041import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
Jonathan Hart5afde492013-10-01 12:30:53 +130042import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120043import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070044import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070045import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070046import net.onrc.onos.ofcontroller.topology.TopologyManager;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120048import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070049import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070050import net.onrc.onos.ofcontroller.util.Port;
51import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080052import net.sf.json.JSONArray;
53import net.sf.json.JSONObject;
54import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080055
Jonathan Hartd1f23252013-06-13 15:17:05 +120056import org.codehaus.jackson.JsonParseException;
57import org.codehaus.jackson.map.JsonMappingException;
58import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070059import org.openflow.protocol.OFFlowMod;
60import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070061import 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;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070086 protected ITopologyService topologyService;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070087 protected ITopologyNetService topologyNetService;
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
Jonathan Hart1912afc2013-10-11 12:02:44 +1300144 private FlowCache flowCache;
145
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700146 protected volatile Topology topology = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200147
Jonathan Hart98957bf2013-07-01 14:49:24 +1200148 protected class TopologyChangeDetector implements Runnable {
149 @Override
150 public void run() {
151 log.debug("Running topology change detection task");
152 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200153 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200154 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
155
156 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200157
158 Iterator<LDUpdate> it = linkUpdates.iterator();
159 while (it.hasNext()){
160 LDUpdate ldu = it.next();
161 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
162 ldu.getDst(), ldu.getDstPort());
163
164 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200165 it.remove();
166 }
167 }
168 }
169
Jonathan Hart64c0b202013-08-20 15:45:07 +1200170 if (!topologyReady) {
171 if (linkUpdates.isEmpty()){
172 //All updates have been seen in network map.
173 //We can check if topology is ready
174 log.debug("No known changes outstanding. Checking topology now");
175 checkStatus();
176 }
177 else {
178 //We know of some link updates that haven't propagated to the database yet
179 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
180 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
181 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200182 }
183 }
184 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700185
Jonathan Hartd1f23252013-06-13 15:17:05 +1200186 private void readGatewaysConfiguration(String gatewaysFilename){
187 File gatewaysFile = new File(gatewaysFilename);
188 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700189
Jonathan Hartd1f23252013-06-13 15:17:05 +1200190 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200191 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
192
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200193 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200194 interfaces = new HashMap<String, Interface>();
195 for (Interface intf : config.getInterfaces()){
196 interfaces.put(intf.getName(), intf);
197 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200198 bgpPeers = new HashMap<InetAddress, BgpPeer>();
199 for (BgpPeer peer : config.getPeers()){
200 bgpPeers.put(peer.getIpAddress(), peer);
201 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200202
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200203 bgpdAttachmentPoint = new SwitchPort(
204 new Dpid(config.getBgpdAttachmentDpid()),
205 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200206
Jonathan Hart2f790d22013-08-15 14:01:24 +1200207 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200208 } catch (JsonParseException e) {
209 log.error("Error in JSON file", e);
210 System.exit(1);
211 } catch (JsonMappingException e) {
212 log.error("Error in JSON file", e);
213 System.exit(1);
214 } catch (IOException e) {
215 log.error("Error reading JSON file", e);
216 System.exit(1);
217 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200218
219 //Populate the interface Patricia Trie
220 for (Interface intf : interfaces.values()) {
221 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
222 interfacePtrie.put(prefix, intf);
223 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700224 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800225
226 @Override
227 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700228 Collection<Class<? extends IFloodlightService>> l
229 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800230 l.add(IBgpRouteService.class);
231 return l;
232 }
233
234 @Override
235 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700236 Map<Class<? extends IFloodlightService>, IFloodlightService> m
237 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800238 m.put(IBgpRouteService.class, this);
Jonathan Hart5afde492013-10-01 12:30:53 +1300239 m.put(IProxyArpService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800240 return m;
241 }
242
pingping-lina2cbfad2013-03-07 08:39:21 +0800243 @Override
244 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700245 Collection<Class<? extends IFloodlightService>> l
246 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800247 l.add(IFloodlightProviderService.class);
248 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700249 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800250 return l;
251 }
252
253 @Override
254 public void init(FloodlightModuleContext context)
255 throws FloodlightModuleException {
256
Jonathan Hart29b972d2013-08-12 23:43:51 +1200257 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200258 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200259
260 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200261
pingping-lina2cbfad2013-03-07 08:39:21 +0800262 // Register floodlight provider and REST handler.
263 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700264 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200265 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200266 restApi = context.getServiceImpl(IRestApiService.class);
267
268 //TODO We'll initialise this here for now, but it should really be done as
269 //part of the controller core
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700270 proxyArp = new ProxyArpManager(floodlightProvider, topologyService, this, restApi);
pingping-lina2cbfad2013-03-07 08:39:21 +0800271
Jonathan Hart98957bf2013-07-01 14:49:24 +1200272 linkUpdates = new ArrayList<LDUpdate>();
273 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
274 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700275
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700276 topologyNetService = new TopologyManager("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200277
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200278 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200279 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
280 HashMultimap.<InetAddress, RibUpdate>create());
281
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200282 pushedPaths = new HashMap<InetAddress, Path>();
283 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200284 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
285
Jonathan Hart1912afc2013-10-11 12:02:44 +1300286 flowCache = new FlowCache(floodlightProvider);
287
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200288 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
289 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
290
Jonathan Hart61ba9372013-05-19 20:10:29 -0700291 //Read in config values
292 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
293 if (bgpdRestIp == null){
294 log.error("BgpdRestIp property not found in config file");
295 System.exit(1);
296 }
297 else {
298 log.info("BgpdRestIp set to {}", bgpdRestIp);
299 }
300
301 routerId = context.getConfigParams(this).get("RouterId");
302 if (routerId == null){
303 log.error("RouterId property not found in config file");
304 System.exit(1);
305 }
306 else {
307 log.info("RouterId set to {}", routerId);
308 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200309
Jonathan Hart9575cb62013-07-05 13:43:49 +1200310 String configFilenameParameter = context.getConfigParams(this).get("configfile");
311 if (configFilenameParameter != null){
312 configFilename = configFilenameParameter;
313 }
314 log.debug("Config file set to {}", configFilename);
315
316 readGatewaysConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200317 }
318
319 @Override
320 public void startUp(FloodlightModuleContext context) {
321 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700322 topologyService.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200323 floodlightProvider.addOFSwitchListener(this);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200324
Jonathan Hart2f790d22013-08-15 14:01:24 +1200325 proxyArp.startUp();
326
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200327 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
328
329 //Retrieve the RIB from BGPd during startup
330 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800331 }
332
Jonathan Hart29b972d2013-08-12 23:43:51 +1200333 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800334 return ptree;
335 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700336
337 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200338 ptree = new PatriciaTrie<RibEntry>(32);
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 getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700342 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800343 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700344
pingping-line2a09ca2013-03-23 09:33:58 +0800345 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700346 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800347 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800348
Jonathan Hart61ba9372013-05-19 20:10:29 -0700349 private void retrieveRib(){
350 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
351 String response = RestClient.get(url);
352
353 if (response.equals("")){
354 return;
355 }
356
357 response = response.replaceAll("\"", "'");
358 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
359 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
360 String router_id = jsonObj.getString("router-id");
361
362 int size = rib_json_array.size();
363
364 log.info("Retrived RIB of {} entries from BGPd", size);
365
366 for (int j = 0; j < size; j++) {
367 JSONObject second_json_object = rib_json_array.getJSONObject(j);
368 String prefix = second_json_object.getString("prefix");
369 String nexthop = second_json_object.getString("nexthop");
370
371 //insert each rib entry into the local rib;
372 String[] substring = prefix.split("/");
373 String prefix1 = substring[0];
374 String mask1 = substring[1];
375
376 Prefix p;
377 try {
378 p = new Prefix(prefix1, Integer.valueOf(mask1));
379 } catch (NumberFormatException e) {
380 log.warn("Wrong mask format in RIB JSON: {}", mask1);
381 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200382 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700383 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
384 continue;
385 }
386
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200387 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200388
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200389 try {
390 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
391 } catch (InterruptedException e) {
392 log.debug("Interrupted while pushing onto update queue");
393 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700394 }
395 }
396
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200397 @Override
398 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200399 try {
400 ribUpdates.put(update);
401 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200402 log.debug("Interrupted while putting on ribUpdates queue", e);
403 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200404 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200405 }
406
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200407 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200408 Prefix prefix = update.getPrefix();
409
Jonathan Hart9ea31212013-08-12 21:40:34 +1200410 log.debug("Processing prefix add {}", prefix);
411
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200412 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200413
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200414 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200415 //There was an existing nexthop for this prefix. This update supersedes that,
416 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200417 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200418 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200419
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200420 if (update.getRibEntry().getNextHop().equals(
421 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200422 //Route originated by SDN domain
423 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200424 log.debug("Own route {} to {}", prefix,
425 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200426 return;
427 }
428
429 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200430 }
431
Jonathan Hart309889c2013-08-13 23:26:24 +1200432 private void _processRibAdd(RibUpdate update) {
433 Prefix prefix = update.getPrefix();
434 RibEntry rib = update.getRibEntry();
435
436 InetAddress dstIpAddress = rib.getNextHop();
437
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200438 //See if we know the MAC address of the next hop
Jonathan Hartabad6a52013-09-30 18:17:21 +1300439 MACAddress nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200440
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200441 //Find the attachment point (egress interface) of the next hop
442 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200443 if (bgpPeers.containsKey(dstIpAddress)) {
444 //Route to a peer
445 log.debug("Route to peer {}", dstIpAddress);
446 BgpPeer peer = bgpPeers.get(dstIpAddress);
447 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200448 }
449 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200450 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200451 log.debug("Route to non-peer {}", dstIpAddress);
452 egressInterface = interfacePtrie.match(
453 new Prefix(dstIpAddress.getAddress(), 32));
454 if (egressInterface == null) {
455 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
456 return;
457 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200458 }
459
460 if (nextHopMacAddress == null) {
461 prefixesWaitingOnArp.put(dstIpAddress,
462 new RibUpdate(Operation.UPDATE, prefix, rib));
463 proxyArp.sendArpRequest(dstIpAddress, this, true);
464 return;
465 }
466 else {
467 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200468 //If the prefix is for a non-peer we need to ensure there's a path,
469 //and push one if there isn't.
470 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200471 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200472 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300473 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200474 pushedPaths.put(dstIpAddress, path);
475 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200476
477 path.incrementUsers();
478 prefixToPath.put(prefix, path);
479 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200480
481 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200482 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
483 }
484 }
485
Jonathan Hartabad6a52013-09-30 18:17:21 +1300486 private void addPrefixFlows(Prefix prefix, Interface egressInterface, MACAddress nextHopMacAddress) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200487 log.debug("Adding flows for prefix {} added, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300488 prefix, nextHopMacAddress);
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200489
490 //We only need one flow mod per switch, so pick one interface on each switch
491 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
492 for (Interface intf : interfaces.values()) {
493 if (!srcInterfaces.containsKey(intf.getDpid())
494 && intf != egressInterface) {
495 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200496 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200497 }
498
499 //Add a flow to rewrite mac for this prefix to all other border switches
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200500 for (Interface srcInterface : srcInterfaces.values()) {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200501 DataPath shortestPath;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700502 if (topology == null) {
503 shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200504 srcInterface.getSwitchPort(),
505 egressInterface.getSwitchPort());
506 }
507 else {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700508 shortestPath = topologyNetService.getTopologyShortestPath(
509 topology, srcInterface.getSwitchPort(),
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200510 egressInterface.getSwitchPort());
511 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200512
513 if (shortestPath == null){
514 log.debug("Shortest path between {} and {} not found",
515 srcInterface.getSwitchPort(),
516 egressInterface.getSwitchPort());
517 return; // just quit here?
518 }
519
520 //Set up the flow mod
521 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
522 .getMessage(OFType.FLOW_MOD);
523
524 fm.setIdleTimeout((short)0)
525 .setHardTimeout((short)0)
526 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
527 .setCookie(MAC_RW_COOKIE)
528 .setCommand(OFFlowMod.OFPFC_ADD)
529 .setPriority(SDNIP_PRIORITY)
530 .setLengthU(OFFlowMod.MINIMUM_LENGTH
531 + OFActionDataLayerDestination.MINIMUM_LENGTH
532 + OFActionOutput.MINIMUM_LENGTH);
533
534 OFMatch match = new OFMatch();
535 match.setDataLayerType(Ethernet.TYPE_IPv4);
536 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
537
538 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
539 fm.setMatch(match);
540
541 //Set up MAC rewrite action
542 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartabad6a52013-09-30 18:17:21 +1300543 macRewriteAction.setDataLayerAddress(nextHopMacAddress.toBytes());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200544
545 //Set up output action
546 OFActionOutput outputAction = new OFActionOutput();
547 outputAction.setMaxLength((short)0xffff);
548 Port outputPort = shortestPath.flowEntries().get(0).outPort();
549 outputAction.setPort(outputPort.value());
550
551 List<OFAction> actions = new ArrayList<OFAction>();
552 actions.add(macRewriteAction);
553 actions.add(outputAction);
554 fm.setActions(actions);
555
Jonathan Hart1912afc2013-10-11 12:02:44 +1300556 pushedFlows.put(prefix, new PushedFlowMod(srcInterface.getDpid(), fm));
557 flowCache.write(srcInterface.getDpid(), fm);
558
559 /*
560 * XXX Rate limit hack!
561 * This should be solved properly by adding a rate limiting
562 * layer on top of the switches if we know they need it.
563 */
564 try {
Jonathan Hart9971e1c2013-09-17 10:47:40 +1200565 Thread.sleep(1);
Jonathan Hart65139e42013-09-13 16:52:25 +1200566 } catch (InterruptedException e) {
567 // TODO handle this properly
568 log.error("Interrupted", e);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200569 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200570 }
571 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200572
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200573 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200574 Prefix prefix = update.getPrefix();
575
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200576 if (ptree.remove(prefix, update.getRibEntry())) {
577 /*
578 * Only delete flows if an entry was actually removed from the trie.
579 * If no entry was removed, the <prefix, nexthop> wasn't there so
580 * it's probably already been removed and we don't need to do anything
581 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200582 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200583 }
584 }
585
586 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
587 deletePrefixFlows(prefix);
588
589 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200590
Jonathan Hart309889c2013-08-13 23:26:24 +1200591 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
592 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200593 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200594
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200595 if (path != null) {
596 //path could be null if we added to the Ptree but didn't push
597 //flows yet because we were waiting to resolve ARP
Jonathan Hart309889c2013-08-13 23:26:24 +1200598
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200599 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200600 if (path.getUsers() <= 0 && !path.isPermanent()) {
601 deletePath(path);
602 pushedPaths.remove(path.getDstIpAddress());
603 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200604 }
605 }
606 }
607
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200608 private void deletePrefixFlows(Prefix prefix) {
609 log.debug("Deleting flows for prefix {}", prefix);
610
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200611 Collection<PushedFlowMod> pushedFlowMods
612 = pushedFlows.removeAll(prefix);
613
614 for (PushedFlowMod pfm : pushedFlowMods) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200615 if (log.isTraceEnabled()) {
616 log.trace("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
617 new Object[] {HexString.toHexString(pfm.getDpid()),
618 pfm.getFlowMod().getMatch().getNetworkDestination() +
619 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
620 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
621 .getDataLayerAddress())});
622 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200623
624 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
625 }
626 }
627
628 private void deletePath(Path path) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200629 log.debug("Deleting flows for path to {}",
630 path.getDstIpAddress().getHostAddress());
631
Jonathan Hart309889c2013-08-13 23:26:24 +1200632 for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200633 if (log.isTraceEnabled()) {
634 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
635 new Object[] {HexString.toHexString(pfm.getDpid()),
636 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
637 });
638 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200639
640 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
641 }
642 }
643
644 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
Jonathan Hart1912afc2013-10-11 12:02:44 +1300645 flowCache.delete(dpid, addFlowMod);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200646 }
647
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200648 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200649 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200650
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700651 /*
652 * On startup we need to calculate a full mesh of paths between all gateway
653 * switches
654 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200655 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700656 //For each border router, calculate and install a path from every other
657 //border switch to said border router. However, don't install the entry
658 //in to the first hop switch, as we need to install an entry to rewrite
659 //for each prefix received. This will be done later when prefixes have
660 //actually been received.
661
Jonathan Hartc824ad02013-07-03 15:58:45 +1200662 for (BgpPeer peer : bgpPeers.values()) {
663 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200664
Jonathan Hart309889c2013-08-13 23:26:24 +1200665 //We know there's not already a Path here pushed, because this is
666 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200667 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200668 path.setPermanent();
669
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200670 //See if we know the MAC address of the peer. If not we can't
671 //do anything until we learn it
Jonathan Hartabad6a52013-09-30 18:17:21 +1300672 MACAddress macAddress = proxyArp.getMacAddress(peer.getIpAddress());
673 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200674 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
675 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200676 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700677
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200678 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
679 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700680 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200681
682 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300683 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700684 }
685 }
686
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200687 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200688 Interface dstInterface = path.getDstInterface();
689
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200690 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
691 dstMacAddress);
692
Jonathan Hart309889c2013-08-13 23:26:24 +1200693 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
694
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200695 for (Interface srcInterface : interfaces.values()) {
696 if (dstInterface.equals(srcInterface.getName())){
697 continue;
698 }
699
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200700 DataPath shortestPath;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700701 if (topology == null) {
702 shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200703 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
704 }
705 else {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700706 shortestPath = topologyNetService.getTopologyShortestPath(topology,
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200707 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
708 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200709
710 if (shortestPath == null){
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200711 log.warn("Shortest path between {} and {} not found",
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200712 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200713 return;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200714 }
715
Jonathan Hart1912afc2013-10-11 12:02:44 +1300716 List<PushedFlowMod> pushedFlowMods = installPath(shortestPath.flowEntries(), dstMacAddress);
717 pushedFlows.addAll(pushedFlowMods);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200718 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200719
720 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200721 }
722
Jonathan Hart309889c2013-08-13 23:26:24 +1200723 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
724 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
725
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700726 //Set up the flow mod
727 OFFlowMod fm =
728 (OFFlowMod) floodlightProvider.getOFMessageFactory()
729 .getMessage(OFType.FLOW_MOD);
730
731 OFActionOutput action = new OFActionOutput();
732 action.setMaxLength((short)0xffff);
733 List<OFAction> actions = new ArrayList<OFAction>();
734 actions.add(action);
735
736 fm.setIdleTimeout((short)0)
737 .setHardTimeout((short)0)
738 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
739 .setCookie(L2_FWD_COOKIE)
740 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hartbdc87462013-09-24 15:03:23 +1200741 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700742 .setActions(actions)
743 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
744
745 //Don't push the first flow entry. We need to push entries in the
746 //first switch based on IP prefix which we don't know yet.
747 for (int i = 1; i < flowEntries.size(); i++){
748 FlowEntry flowEntry = flowEntries.get(i);
749
750 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200751 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700752 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
753 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
754
755 fm.setMatch(match);
756
Jonathan Hart1912afc2013-10-11 12:02:44 +1300757 flowMods.add(new PushedFlowMod(flowEntry.dpid().value(), fm));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700758
Jonathan Hart1912afc2013-10-11 12:02:44 +1300759 flowCache.write(flowEntry.dpid().value(), fm);
760
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700761 try {
762 fm = fm.clone();
763 } catch (CloneNotSupportedException e1) {
764 log.error("Failure cloning flow mod", e1);
765 }
766 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200767
768 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700769 }
770
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200771 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200772 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200773 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
774
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700775 DataPath path = topologyNetService.getDatabaseShortestPath(
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200776 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
777
778 if (path == null){
779 log.debug("Unable to compute path for BGP traffic for {}",
780 bgpPeer.getIpAddress());
781 continue;
782 }
783
784 //Set up the flow mod
785 OFFlowMod fm =
786 (OFFlowMod) floodlightProvider.getOFMessageFactory()
787 .getMessage(OFType.FLOW_MOD);
788
789 OFActionOutput action = new OFActionOutput();
790 action.setMaxLength((short)0xffff);
791 List<OFAction> actions = new ArrayList<OFAction>();
792 actions.add(action);
793
794 fm.setIdleTimeout((short)0)
795 .setHardTimeout((short)0)
796 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
797 .setCookie(BGP_COOKIE)
798 .setCommand(OFFlowMod.OFPFC_ADD)
799 .setPriority(SDNIP_PRIORITY)
800 .setActions(actions)
801 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
802
803 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
804 OFMatch forwardMatchSrc = new OFMatch();
805
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200806 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
807 + "/32";
808 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
809 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200810
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200811 //Common match fields
812 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200813 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300814 //forwardMatchSrc.setTransportDestination(BGP_PORT);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200815 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
816 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
817
818
819 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
820
821 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
822 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
823
824 OFMatch forwardMatchDst = forwardMatchSrc.clone();
825
826 forwardMatchSrc.setTransportSource(BGP_PORT);
827 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
828 forwardMatchDst.setTransportDestination(BGP_PORT);
829 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
830
831 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
832 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
833
834 OFMatch reverseMatchDst = reverseMatchSrc.clone();
835
836 reverseMatchSrc.setTransportSource(BGP_PORT);
837 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
838 reverseMatchDst.setTransportDestination(BGP_PORT);
839 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
840
841 fm.setMatch(forwardMatchSrc);
842
Jonathan Hart38c84932013-08-10 17:49:27 +1200843 OFMatch forwardIcmpMatch = new OFMatch();
844 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
845 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
846 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
847 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
848
849 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
850 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
851 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
852
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200853 for (FlowEntry flowEntry : path.flowEntries()){
854 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
855 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200856 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200857 try {
858 forwardFlowModSrc = fm.clone();
859 forwardFlowModDst = fm.clone();
860 reverseFlowModSrc = fm.clone();
861 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200862 forwardIcmp = fm.clone();
863 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200864 } catch (CloneNotSupportedException e) {
865 log.warn("Clone failed", e);
866 continue;
867 }
868
869 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
870 forwardFlowModSrc.setMatch(forwardMatchSrc);
871 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
872 .setPort(flowEntry.outPort().value());
873
874 forwardMatchDst.setInputPort(flowEntry.inPort().value());
875 forwardFlowModDst.setMatch(forwardMatchDst);
876 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
877 .setPort(flowEntry.outPort().value());
878
879 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
880 reverseFlowModSrc.setMatch(reverseMatchSrc);
881 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
882 .setPort(flowEntry.inPort().value());
883
884 reverseMatchDst.setInputPort(flowEntry.outPort().value());
885 reverseFlowModDst.setMatch(reverseMatchDst);
886 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
887 .setPort(flowEntry.inPort().value());
888
Jonathan Hart38c84932013-08-10 17:49:27 +1200889 ((OFActionOutput)forwardIcmp.getActions().get(0))
890 .setPort(flowEntry.outPort().value());
891 forwardIcmp.setMatch(forwardIcmpMatch);
892
893 ((OFActionOutput)reverseIcmp.getActions().get(0))
894 .setPort(flowEntry.inPort().value());
895 reverseIcmp.setMatch(reverseIcmpMatch);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200896
Jonathan Hart1912afc2013-10-11 12:02:44 +1300897 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(6);
898 flowModList.add(forwardFlowModSrc);
899 flowModList.add(forwardFlowModDst);
900 flowModList.add(reverseFlowModSrc);
901 flowModList.add(reverseFlowModDst);
902 flowModList.add(forwardIcmp);
903 flowModList.add(reverseIcmp);
904 flowCache.write(flowEntry.dpid().value(), flowModList);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200905 }
906 }
907 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200908
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200909 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +1300910 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
911 log.debug("Received ARP response: {} => {}",
912 ipAddress.getHostAddress(), macAddress);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200913
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200914 /*
915 * We synchronize on this to prevent changes to the ptree while we're pushing
916 * flows to the switches. If the ptree changes, the ptree and switches
917 * could get out of sync.
918 */
919 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200920 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200921
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200922 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200923 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300924 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200925 path.getDstInterface().getSwitchPort()});
926 //These paths should always be to BGP peers. Paths to non-peers are
927 //handled once the first prefix is ready to push
928 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200929 //A path already got pushed to this endpoint while we were waiting
930 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200931 if (path.isPermanent()) {
932 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200933 }
934 }
935 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300936 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200937 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200938 }
939 }
940
Jonathan Hart309889c2013-08-13 23:26:24 +1200941 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
942
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200943 for (RibUpdate update : prefixesToPush) {
944 //These will always be adds
945
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200946 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200947 if (rib != null && rib.equals(update.getRibEntry())) {
948 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200949 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200950 //We only push prefix flows if the prefix is still in the ptree
951 //and the next hop is the same as our update. The prefix could
952 //have been removed while we were waiting for the ARP, or the
953 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200954 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200955 } else {
956 log.debug("Received ARP response, but {},{} is no longer in ptree",
957 update.getPrefix(), update.getRibEntry());
958 }
959 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200960 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200961 }
962
Jonathan Hartc82051c2013-08-24 15:12:20 +1200963 private void setupArpFlows() {
964 OFMatch match = new OFMatch();
965 match.setDataLayerType(Ethernet.TYPE_ARP);
966 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
967
968 OFFlowMod fm = new OFFlowMod();
969 fm.setMatch(match);
970
971 OFActionOutput action = new OFActionOutput();
972 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
973 action.setMaxLength((short)0xffff);
974 List<OFAction> actions = new ArrayList<OFAction>(1);
975 actions.add(action);
976 fm.setActions(actions);
977
978 fm.setIdleTimeout((short)0)
979 .setHardTimeout((short)0)
980 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
981 .setCookie(0)
982 .setCommand(OFFlowMod.OFPFC_ADD)
983 .setPriority(ARP_PRIORITY)
984 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
985
986 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +1300987 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +1200988 }
989 }
990
Jonathan Hartf886fa12013-09-18 14:46:29 +1200991 private void setupDefaultDropFlows() {
992 OFFlowMod fm = new OFFlowMod();
993 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +1200994 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Jonathan Hartf886fa12013-09-18 14:46:29 +1200995
996 fm.setIdleTimeout((short)0)
997 .setHardTimeout((short)0)
998 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
999 .setCookie(0)
1000 .setCommand(OFFlowMod.OFPFC_ADD)
1001 .setPriority((short)0)
1002 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
1003
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001004 OFFlowMod fmLLDP;
1005 OFFlowMod fmBDDP;
1006 try {
1007 fmLLDP = fm.clone();
1008 fmBDDP = fm.clone();
1009 } catch (CloneNotSupportedException e1) {
1010 log.error("Error cloning flow mod", e1);
1011 return;
1012 }
1013
1014 OFMatch matchLLDP = new OFMatch();
1015 matchLLDP.setDataLayerType((short)0x8942);
1016 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1017 fmLLDP.setMatch(matchLLDP);
1018
1019 OFMatch matchBDDP = new OFMatch();
1020 matchBDDP.setDataLayerType((short)0x88cc);
1021 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1022 fmBDDP.setMatch(matchBDDP);
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
1030 fmLLDP.setActions(actions);
1031 fmBDDP.setActions(actions);
1032
1033 fmLLDP.setPriority(ARP_PRIORITY);
1034 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1035 fmBDDP.setPriority(ARP_PRIORITY);
1036 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1037
Jonathan Hart1912afc2013-10-11 12:02:44 +13001038 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1039 flowModList.add(fm);
1040 flowModList.add(fmLLDP);
1041 flowModList.add(fmBDDP);
1042
Jonathan Hartf886fa12013-09-18 14:46:29 +12001043 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001044 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001045 }
1046 }
1047
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001048 private void beginRouting(){
1049 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001050 topology = topologyNetService.newDatabaseTopology();
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001051
Jonathan Hartc82051c2013-08-24 15:12:20 +12001052 setupArpFlows();
Jonathan Hartf886fa12013-09-18 14:46:29 +12001053 setupDefaultDropFlows();
Jonathan Hartc82051c2013-08-24 15:12:20 +12001054
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001055 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001056 setupFullMesh();
Jonathan Harte7694532013-09-12 12:34:46 +12001057
1058 //Suppress link discovery on external-facing router ports
1059 for (Interface intf : interfaces.values()) {
1060 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1061 }
1062
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001063 bgpUpdatesExecutor.execute(new Runnable() {
1064 @Override
1065 public void run() {
1066 doUpdatesThread();
1067 }
1068 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001069 }
1070
1071 private void checkSwitchesConnected(){
1072 for (String dpid : switches){
1073 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1074 log.debug("Not all switches are here yet");
1075 return;
1076 }
1077 }
1078 switchesConnected = true;
1079 }
1080
Jonathan Hartc824ad02013-07-03 15:58:45 +12001081 //Actually we only need to go half way round to verify full mesh connectivity
1082 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001083 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001084 for (Interface dstInterface : interfaces.values()) {
1085 for (Interface srcInterface : interfaces.values()) {
1086 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001087 continue;
1088 }
1089
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001090 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001091 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001092
1093 if (shortestPath == null){
1094 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001095 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001096 return;
1097 }
1098 }
1099 }
1100 topologyReady = true;
1101 }
1102
1103 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001104 if (!switchesConnected){
1105 checkSwitchesConnected();
1106 }
1107 boolean oldTopologyReadyStatus = topologyReady;
1108 if (switchesConnected && !topologyReady){
1109 checkTopologyReady();
1110 }
1111 if (!oldTopologyReadyStatus && topologyReady){
1112 beginRouting();
1113 }
1114 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001115
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001116 private void doUpdatesThread() {
1117 boolean interrupted = false;
1118 try {
1119 while (true) {
1120 try {
1121 RibUpdate update = ribUpdates.take();
1122 switch (update.getOperation()){
1123 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001124 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001125 break;
1126 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001127 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001128 break;
1129 }
1130 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001131 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001132 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001133 } catch (Exception e) {
1134 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001135 }
1136 }
1137 } finally {
1138 if (interrupted) {
1139 Thread.currentThread().interrupt();
1140 }
1141 }
1142 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001143
1144 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001145 public void topologyChanged() {
1146 if (topologyReady) {
1147 return;
1148 }
1149
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001150 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001151 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001152 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1153 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001154 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001155 refreshNeeded = true;
1156 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001157
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001158 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001159
Jonathan Hart98957bf2013-07-01 14:49:24 +12001160 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1161 synchronized (linkUpdates) {
1162 linkUpdates.add(ldu);
1163 }
1164 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001165 }
1166
Jonathan Hart64c0b202013-08-20 15:45:07 +12001167 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001168 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001169 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001170 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001171
1172 @Override
1173 public void addedSwitch(IOFSwitch sw) {
1174 if (!topologyReady) {
1175 sw.clearAllFlowMods();
1176 }
Jonathan Hart1912afc2013-10-11 12:02:44 +13001177
1178 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001179 }
1180
1181 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001182 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001183
1184 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001185 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001186
1187 @Override
1188 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001189 return "BgpRoute";
1190 }
1191
1192 /*
1193 * ILayer3InfoService methods
1194 */
1195
1196 @Override
1197 public boolean isInterfaceAddress(InetAddress address) {
1198 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1199 return (intf != null && intf.getIpAddress().equals(address));
1200 }
1201
1202 @Override
1203 public boolean inConnectedNetwork(InetAddress address) {
1204 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1205 return (intf != null && !intf.getIpAddress().equals(address));
1206 }
1207
1208 @Override
1209 public boolean fromExternalNetwork(long inDpid, short inPort) {
1210 for (Interface intf : interfaces.values()) {
1211 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1212 return true;
1213 }
1214 }
1215 return false;
1216 }
1217
1218 @Override
1219 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1220 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1221 }
1222
1223 @Override
1224 public boolean hasLayer3Configuration() {
1225 return !interfaces.isEmpty();
1226 }
1227
1228 @Override
1229 public MACAddress getRouterMacAddress() {
1230 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001231 }
Jonathan Hart5afde492013-10-01 12:30:53 +13001232
1233 /*
1234 * TODO This is a hack to get the REST API to work for ProxyArpManager.
1235 * The REST API is currently tied to the Floodlight module system and we
1236 * need to separate it to allow ONOS modules to use it. For now we will
1237 * proxy calls through to the ProxyArpManager (which is not a Floodlight
1238 * module) through this class which is a module.
1239 */
1240 @Override
1241 public MACAddress getMacAddress(InetAddress ipAddress) {
1242 return proxyArp.getMacAddress(ipAddress);
1243 }
1244
1245 @Override
1246 public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
1247 boolean retry) {
1248 proxyArp.sendArpRequest(ipAddress, requester, retry);
1249 }
1250
1251 @Override
1252 public List<String> getMappings() {
1253 return proxyArp.getMappings();
1254 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001255}