blob: 745e27b511256c212304b19b042fd2822053f63f [file] [log] [blame]
Jonathan Hart8f6dc092014-04-18 15:56:43 -07001package net.onrc.onos.apps.sdnip;
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 Hartf6978ce2014-06-23 11:20:04 -07009import 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;
pingping-lina2cbfad2013-03-07 08:39:21 +080028import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120029import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0961fe82014-04-03 09:56:25 -070030import net.onrc.onos.apps.proxyarp.IArpRequester;
31import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart8f6dc092014-04-18 15:56:43 -070032import net.onrc.onos.apps.sdnip.RibUpdate.Operation;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070033import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutable;
Komal Shah399a2922014-05-28 01:57:40 -070034import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutableNew;
35import net.onrc.onos.core.intent.IntentOperation;
36import net.onrc.onos.core.intent.IntentOperationList;
37import net.onrc.onos.core.intent.ShortestPathIntent;
38import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
Jonathan Hart23701d12014-04-03 10:45:48 -070039import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harta99ec672014-04-03 11:30:34 -070040import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070041import net.onrc.onos.core.main.config.IConfigInfoService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070042import net.onrc.onos.core.packet.Ethernet;
43import net.onrc.onos.core.packet.IPv4;
Komal Shah399a2922014-05-28 01:57:40 -070044import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart23701d12014-04-03 10:45:48 -070045import net.onrc.onos.core.util.CallerId;
46import net.onrc.onos.core.util.DataPath;
47import net.onrc.onos.core.util.Dpid;
48import net.onrc.onos.core.util.FlowEntryAction;
49import net.onrc.onos.core.util.FlowEntryActions;
50import net.onrc.onos.core.util.FlowEntryMatch;
51import net.onrc.onos.core.util.FlowId;
52import net.onrc.onos.core.util.FlowPath;
53import net.onrc.onos.core.util.FlowPathFlags;
54import net.onrc.onos.core.util.FlowPathType;
55import net.onrc.onos.core.util.FlowPathUserState;
56import net.onrc.onos.core.util.IPv4Net;
Yuta HIGUCHIfb564502014-06-16 21:29:00 -070057import net.onrc.onos.core.util.PortNumber;
Jonathan Hart23701d12014-04-03 10:45:48 -070058import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080059import net.sf.json.JSONArray;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070060import net.sf.json.JSONException;
pingping-line2a09ca2013-03-23 09:33:58 +080061import net.sf.json.JSONObject;
62import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080063
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070064import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120065import org.codehaus.jackson.JsonParseException;
66import org.codehaus.jackson.map.JsonMappingException;
67import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070068import org.openflow.protocol.OFFlowMod;
69import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070070import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120071import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070072import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070073import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120074import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080075import org.slf4j.Logger;
76import org.slf4j.LoggerFactory;
77
Jonathan Hart4dfc3652013-08-02 20:22:36 +120078import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120079import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120080import com.google.common.collect.Multimaps;
81import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120082import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120083import com.google.common.util.concurrent.ThreadFactoryBuilder;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070084import com.googlecode.concurrenttrees.radix.RadixTree;
85import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
86import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
87import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120088
Jonathan Hart8f6dc092014-04-18 15:56:43 -070089public class SdnIp implements IFloodlightModule, ISdnIpService,
Ray Milkey269ffb92014-04-03 14:43:30 -070090 IArpRequester,
91 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070092
Jonathan Hart8f6dc092014-04-18 15:56:43 -070093 private static final Logger log = LoggerFactory.getLogger(SdnIp.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080094
Ray Milkey269ffb92014-04-03 14:43:30 -070095 private IFloodlightProviderService floodlightProvider;
96 private ILinkDiscoveryService linkDiscoveryService;
97 private IRestApiService restApi;
98 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070099
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700100 private InvertedRadixTree<RibEntry> bgpRoutes;
101 private InvertedRadixTree<Interface> interfaceRoutes;
102
Ray Milkey269ffb92014-04-03 14:43:30 -0700103 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700104
Ray Milkey269ffb92014-04-03 14:43:30 -0700105 private String bgpdRestIp;
106 private String routerId;
Ray Milkey5df613b2014-04-15 10:50:56 -0700107 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
108 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700109
Komal Shah399a2922014-05-28 01:57:40 -0700110 /* ShortestPath Intent Variables */
111 private final String callerId = "SdnIp";
112 private IControllerRegistryService controllerRegistryService;
113 private IPathCalcRuntimeService pathRuntime;
114 /* Shortest Intent Path Variables */
115
Ray Milkey2476cac2014-04-08 11:03:21 -0700116 private static final short ARP_PRIORITY = 20;
Ray Milkey5d406012014-04-08 14:44:41 -0700117
Jonathan Hart938a0152014-04-07 18:27:31 -0700118 // The fields below are unused after the move to FlowManager.
119 // Remove them if no longer needed.
120 /*
121 // We need to identify our flows somehow, in lieu of an OS-wide mechanism
122 // to hand out cookie IDs to prevent conflicts.
123 private static final long APP_COOKIE = 0xa0000000000000L;
124 // Cookie for flows that do L2 forwarding within SDN domain to egress routers
125 private static final long L2_FWD_COOKIE = APP_COOKIE + 1;
126 // Cookie for flows in ingress switches that rewrite the MAC address
127 private static final long MAC_RW_COOKIE = APP_COOKIE + 2;
128 // Cookie for flows that setup BGP paths
129 private static final long BGP_COOKIE = APP_COOKIE + 3;
130 // Forwarding uses priority 0, and the mac rewrite entries in ingress switches
131 // need to be higher priority than this otherwise the rewrite may not get done
132 private static final short SDNIP_PRIORITY = 10;
133 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700134
Ray Milkey2476cac2014-04-08 11:03:21 -0700135 private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700136
Jonathan Hart938a0152014-04-07 18:27:31 -0700137 private static final int TOPO_DETECTION_WAIT = 2; // seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700138
Jonathan Hart938a0152014-04-07 18:27:31 -0700139 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700140 private List<String> switches;
141 private Map<String, Interface> interfaces;
142 private Map<InetAddress, BgpPeer> bgpPeers;
143 private SwitchPort bgpdAttachmentPoint;
144 private MACAddress bgpdMacAddress;
145 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700146
Jonathan Hart938a0152014-04-07 18:27:31 -0700147 // True when all switches have connected
Ray Milkey269ffb92014-04-03 14:43:30 -0700148 private volatile boolean switchesConnected = false;
Jonathan Hart938a0152014-04-07 18:27:31 -0700149 // True when we have a full mesh of shortest paths between gateways
Ray Milkey269ffb92014-04-03 14:43:30 -0700150 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200151
Jonathan Hart938a0152014-04-07 18:27:31 -0700152 private List<LDUpdate> linkUpdates;
Ray Milkey269ffb92014-04-03 14:43:30 -0700153 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700154
Ray Milkey269ffb92014-04-03 14:43:30 -0700155 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700156
Ray Milkey269ffb92014-04-03 14:43:30 -0700157 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700158
Ray Milkey269ffb92014-04-03 14:43:30 -0700159 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700160
Ray Milkey269ffb92014-04-03 14:43:30 -0700161 private Map<InetAddress, Path> pushedPaths;
162 private Map<Prefix, Path> prefixToPath;
163 // private Multimap<Prefix, PushedFlowMod> pushedFlows;
164 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700165
Ray Milkey269ffb92014-04-03 14:43:30 -0700166 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700167
Ray Milkey269ffb92014-04-03 14:43:30 -0700168 // TODO: Fix for the new Topology Network Graph
169 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700170
Ray Milkey269ffb92014-04-03 14:43:30 -0700171 private class TopologyChangeDetector implements Runnable {
172 @Override
173 public void run() {
174 log.debug("Running topology change detection task");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700175 // TODO: Fix the code below after topoLinkService was removed
176 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700177 synchronized (linkUpdates) {
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700178
Ray Milkey269ffb92014-04-03 14:43:30 -0700179 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700180
Ray Milkey269ffb92014-04-03 14:43:30 -0700181 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700182
Ray Milkey269ffb92014-04-03 14:43:30 -0700183 Iterator<LDUpdate> it = linkUpdates.iterator();
184 while (it.hasNext()){
185 LDUpdate ldu = it.next();
186 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
187 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700188
Ray Milkey269ffb92014-04-03 14:43:30 -0700189 if (activeLinks.contains(l)){
190 it.remove();
191 }
192 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700193 }
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700194 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700195
Ray Milkey269ffb92014-04-03 14:43:30 -0700196 if (!topologyReady) {
197 if (linkUpdates.isEmpty()) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700198 // All updates have been seen in network map.
199 // We can check if topology is ready
Ray Milkey269ffb92014-04-03 14:43:30 -0700200 log.debug("No known changes outstanding. Checking topology now");
201 checkStatus();
202 } else {
Jonathan Hart938a0152014-04-07 18:27:31 -0700203 // We know of some link updates that haven't propagated to the database yet
Ray Milkey269ffb92014-04-03 14:43:30 -0700204 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
205 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
206 }
207 }
208 }
209 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700210
Ray Milkey269ffb92014-04-03 14:43:30 -0700211 private void readConfiguration(String configFilename) {
212 File gatewaysFile = new File(configFilename);
213 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700214
Ray Milkey269ffb92014-04-03 14:43:30 -0700215 try {
216 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700217
Ray Milkey269ffb92014-04-03 14:43:30 -0700218 switches = config.getSwitches();
219 interfaces = new HashMap<String, Interface>();
220 for (Interface intf : config.getInterfaces()) {
221 interfaces.put(intf.getName(), intf);
222 }
223 bgpPeers = new HashMap<InetAddress, BgpPeer>();
224 for (BgpPeer peer : config.getPeers()) {
225 bgpPeers.put(peer.getIpAddress(), peer);
226 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700227
Ray Milkey269ffb92014-04-03 14:43:30 -0700228 bgpdAttachmentPoint = new SwitchPort(
229 new Dpid(config.getBgpdAttachmentDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700230 new PortNumber(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700231
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 bgpdMacAddress = config.getBgpdMacAddress();
233 vlan = config.getVlan();
234 } catch (JsonParseException e) {
235 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700236 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700237 } catch (JsonMappingException e) {
238 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700239 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700240 } catch (IOException e) {
241 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700242 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700243 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700244
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700245 // Populate the interface Patricia Tree
Ray Milkey269ffb92014-04-03 14:43:30 -0700246 for (Interface intf : interfaces.values()) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700247 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
248 intf.getPrefixLength());
249 interfaceRoutes.put(prefix.toBinaryString(), intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700250 }
251 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700252
Ray Milkey269ffb92014-04-03 14:43:30 -0700253 @Override
254 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
255 Collection<Class<? extends IFloodlightService>> l
256 = new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700257 l.add(ISdnIpService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700258 l.add(IConfigInfoService.class);
259 return l;
260 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700261
Ray Milkey269ffb92014-04-03 14:43:30 -0700262 @Override
263 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
264 Map<Class<? extends IFloodlightService>, IFloodlightService> m
265 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700266 m.put(ISdnIpService.class, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700267 m.put(IConfigInfoService.class, this);
268 return m;
269 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800270
Ray Milkey269ffb92014-04-03 14:43:30 -0700271 @Override
272 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
273 Collection<Class<? extends IFloodlightService>> l
274 = new ArrayList<Class<? extends IFloodlightService>>();
275 l.add(IFloodlightProviderService.class);
276 l.add(IRestApiService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700277 l.add(IControllerRegistryService.class);
278 l.add(IPathCalcRuntimeService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700279 return l;
280 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700281
Ray Milkey269ffb92014-04-03 14:43:30 -0700282 @Override
283 public void init(FloodlightModuleContext context)
284 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700285
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700286 bgpRoutes = new ConcurrentInvertedRadixTree<>(
287 new DefaultByteArrayNodeFactory());
288 interfaceRoutes = new ConcurrentInvertedRadixTree<>(
289 new DefaultByteArrayNodeFactory());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700290
Ray Milkey269ffb92014-04-03 14:43:30 -0700291 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700292
Ray Milkey269ffb92014-04-03 14:43:30 -0700293 // Register floodlight provider and REST handler.
294 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
295 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
296 restApi = context.getServiceImpl(IRestApiService.class);
297 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800298
Komal Shah399a2922014-05-28 01:57:40 -0700299 controllerRegistryService = context.getServiceImpl(IControllerRegistryService.class);
300 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700301 linkUpdates = new ArrayList<LDUpdate>();
302 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
303 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700304
Ray Milkey269ffb92014-04-03 14:43:30 -0700305 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
306 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
307 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700308
Ray Milkey269ffb92014-04-03 14:43:30 -0700309 pushedPaths = new HashMap<InetAddress, Path>();
310 prefixToPath = new HashMap<Prefix, Path>();
311// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
312 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700313
Ray Milkey269ffb92014-04-03 14:43:30 -0700314 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700315
Ray Milkey269ffb92014-04-03 14:43:30 -0700316 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
317 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700318
Jonathan Hart938a0152014-04-07 18:27:31 -0700319 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700320 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
321 if (bgpdRestIp == null) {
322 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700323 throw new ConfigurationRuntimeException(
324 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700325 } else {
326 log.info("BgpdRestIp set to {}", bgpdRestIp);
327 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700328
Ray Milkey269ffb92014-04-03 14:43:30 -0700329 routerId = context.getConfigParams(this).get("RouterId");
330 if (routerId == null) {
331 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700332 throw new ConfigurationRuntimeException(
333 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700334 } else {
335 log.info("RouterId set to {}", routerId);
336 }
pingping-linba5c52f2014-02-11 16:52:01 -0800337
Ray Milkey269ffb92014-04-03 14:43:30 -0700338 String configFilenameParameter = context.getConfigParams(this).get("configfile");
339 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700340 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700341 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700342 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700343
Ray Milkey5df613b2014-04-15 10:50:56 -0700344 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700345 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700346
Ray Milkey269ffb92014-04-03 14:43:30 -0700347 @Override
348 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700349 restApi.addRestletRoutable(new SdnIpWebRoutable());
Komal Shah399a2922014-05-28 01:57:40 -0700350 restApi.addRestletRoutable(new SdnIpWebRoutableNew());
Ray Milkey269ffb92014-04-03 14:43:30 -0700351 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800352
Jonathan Hart938a0152014-04-07 18:27:31 -0700353 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700354 retrieveRib();
355 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800356
Ray Milkey269ffb92014-04-03 14:43:30 -0700357 @Override
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700358 public RadixTree<RibEntry> getPtree() {
359 return bgpRoutes;
Ray Milkey269ffb92014-04-03 14:43:30 -0700360 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700361
Ray Milkey269ffb92014-04-03 14:43:30 -0700362 @Override
363 public void clearPtree() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700364 log.warn("Clear table operation not supported");
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700366
Ray Milkey269ffb92014-04-03 14:43:30 -0700367 @Override
Jonathan Hart31e15f12014-04-10 10:33:00 -0700368 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700369 return bgpdRestIp;
370 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700371
Ray Milkey269ffb92014-04-03 14:43:30 -0700372 @Override
373 public String getRouterId() {
374 return routerId;
375 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700376
Ray Milkey269ffb92014-04-03 14:43:30 -0700377 private void retrieveRib() {
378 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
379 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700380
Jonathan Hart938a0152014-04-07 18:27:31 -0700381 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700382 return;
383 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700384
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700385 try {
386 response = response.replaceAll("\"", "'");
387 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
388 JSONArray ribArray = jsonObj.getJSONArray("rib");
389 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700390
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700391 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700392
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700393 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700394
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700395 for (int j = 0; j < size; j++) {
396 JSONObject ribEntry = ribArray.getJSONObject(j);
397 String prefix = ribEntry.getString("prefix");
398 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700399
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700400 // Insert each rib entry into the local rib
401 String[] substring = prefix.split("/");
402 String prefix1 = substring[0];
403 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700404
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700405 Prefix p;
406 try {
407 p = new Prefix(prefix1, Integer.parseInt(mask1));
408 } catch (NumberFormatException e) {
409 log.warn("Wrong mask format in RIB JSON: {}", mask1);
410 continue;
411 } catch (IllegalArgumentException e1) {
412 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
413 continue;
414 }
415
416 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
417
418 try {
419 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
420 } catch (InterruptedException e) {
421 log.debug("Interrupted while pushing onto update queue");
422 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700423 }
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700424 } catch (JSONException e) {
425 // TODO don't parse JSON manually
426 log.error("Error parsing inital route table JSON:", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700427 }
428 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700429
Ray Milkey269ffb92014-04-03 14:43:30 -0700430 @Override
431 public void newRibUpdate(RibUpdate update) {
432 try {
433 ribUpdates.put(update);
434 } catch (InterruptedException e) {
435 log.debug("Interrupted while putting on ribUpdates queue", e);
436 Thread.currentThread().interrupt();
437 }
438 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700439
Jonathan Hart938a0152014-04-07 18:27:31 -0700440 public void processRibAdd(RibUpdate update) {
441 synchronized (this) {
442 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700443
Jonathan Hart938a0152014-04-07 18:27:31 -0700444 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700445
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700446 RibEntry rib = bgpRoutes.put(prefix.toBinaryString(), update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700447
Jonathan Hart938a0152014-04-07 18:27:31 -0700448 if (rib != null && !rib.equals(update.getRibEntry())) {
449 // There was an existing nexthop for this prefix. This update supersedes that,
450 // so we need to remove the old flows for this prefix from the switches
Ray Milkey7531a342014-04-11 15:08:12 -0700451 executeDeletePrefix(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700452 }
Ray Milkey5d406012014-04-08 14:44:41 -0700453
Jonathan Hart938a0152014-04-07 18:27:31 -0700454 if (update.getRibEntry().getNextHop().equals(
455 InetAddresses.forString("0.0.0.0"))) {
456 // Route originated by SDN domain
457 // We don't handle these at the moment
458 log.debug("Own route {} to {}", prefix,
459 update.getRibEntry().getNextHop().getHostAddress());
460 return;
461 }
Ray Milkey5d406012014-04-08 14:44:41 -0700462
Ray Milkey7531a342014-04-11 15:08:12 -0700463 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700464 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700465 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700466
Ray Milkey7531a342014-04-11 15:08:12 -0700467 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700468 // TODO: Fix the code below. Note that "deviceStorage" was removed.
469
470 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700471 Prefix prefix = update.getPrefix();
472 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700473
Ray Milkey269ffb92014-04-03 14:43:30 -0700474 InetAddress dstIpAddress = rib.getNextHop();
475 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800476
Ray Milkey269ffb92014-04-03 14:43:30 -0700477 // See if we know the MAC address of the next hop
478 // TODO if we do not treat the next hop as a device in the future, we need to update this
Ray Milkey269ffb92014-04-03 14:43:30 -0700479 IDeviceObject nextHopDevice =
480 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700481
Ray Milkey269ffb92014-04-03 14:43:30 -0700482 if (nextHopDevice == null){
483 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
484 prefixesWaitingOnArp.put(dstIpAddress,
485 new RibUpdate(Operation.UPDATE, prefix, rib));
486 proxyArp.sendArpRequest(dstIpAddress, this, true);
487 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800488
Ray Milkey269ffb92014-04-03 14:43:30 -0700489 }
490 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700491
Ray Milkey269ffb92014-04-03 14:43:30 -0700492 // Find the attachment point (egress interface) of the next hop
493 Interface egressInterface = null;
494 if (bgpPeers.containsKey(dstIpAddress)) {
495 //Route to a peer
496 log.debug("Route to peer {}", dstIpAddress);
497 BgpPeer peer = bgpPeers.get(dstIpAddress);
498 egressInterface = interfaces.get(peer.getInterfaceName());
499 } else {
500 //Route to non-peer
501 log.debug("Route to non-peer {}", dstIpAddress);
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700502 egressInterface = interfacePtree.match(
Ray Milkey269ffb92014-04-03 14:43:30 -0700503 new Prefix(dstIpAddress.getAddress(), 32));
504 if (egressInterface == null) {
505 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
506 return;
507 }
508 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700509
Ray Milkey269ffb92014-04-03 14:43:30 -0700510 if (nextHopMacAddress == null) {
511 prefixesWaitingOnArp.put(dstIpAddress,
512 new RibUpdate(Operation.UPDATE, prefix, rib));
513 proxyArp.sendArpRequest(dstIpAddress, this, true);
514 return;
515 } else {
516 if (!bgpPeers.containsKey(dstIpAddress)) {
517 //If the prefix is for a non-peer we need to ensure there's a path,
518 //and push one if there isn't.
519 Path path = pushedPaths.get(dstIpAddress);
520 if (path == null) {
521 path = new Path(egressInterface, dstIpAddress);
522 calculateAndPushPath(path, nextHopMacAddress);
523 pushedPaths.put(dstIpAddress, path);
524 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700525
Ray Milkey269ffb92014-04-03 14:43:30 -0700526 path.incrementUsers();
527 prefixToPath.put(prefix, path);
528 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700529
Ray Milkey269ffb92014-04-03 14:43:30 -0700530 //For all prefixes we need to add the first-hop mac-rewriting flows
531 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
532 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700533 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700534 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700535
Ray Milkey269ffb92014-04-03 14:43:30 -0700536 /**
537 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
Ray Milkeyb41100a2014-04-10 10:42:15 -0700538 * to all other border switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700539 */
540 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
541 MACAddress nextHopMacAddress) {
542 log.debug("Adding flows for prefix {}, next hop mac {}",
543 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700544
Ray Milkey269ffb92014-04-03 14:43:30 -0700545 FlowPath flowPath = new FlowPath();
546 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700547
Ray Milkey269ffb92014-04-03 14:43:30 -0700548 // Set flowPath FlowPathType and FlowPathUserState
549 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
550 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800551
Ray Milkey269ffb92014-04-03 14:43:30 -0700552 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
553 // only to the first-host switches
554 FlowPathFlags flowPathFlags = new FlowPathFlags();
555 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
556 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800557
Ray Milkey269ffb92014-04-03 14:43:30 -0700558 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700559 SwitchPort dstPort =
560 new SwitchPort(new Dpid(egressInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700561 new PortNumber(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800562
Ray Milkey269ffb92014-04-03 14:43:30 -0700563 // We only need one flow mod per switch, so pick one interface on each switch
564 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
565 for (Interface intf : interfaces.values()) {
566 if (!srcInterfaces.containsKey(intf.getDpid())
567 && !intf.equals(egressInterface)) {
568 srcInterfaces.put(intf.getDpid(), intf);
569 }
570 }
571 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800572
Ray Milkey269ffb92014-04-03 14:43:30 -0700573 if (egressInterface.equals(srcInterface)) {
574 continue;
575 }
pingping-linba5c52f2014-02-11 16:52:01 -0800576
Ray Milkey269ffb92014-04-03 14:43:30 -0700577 // Create flowPath FlowId
578 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800579
Ray Milkey269ffb92014-04-03 14:43:30 -0700580 // Create DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700581 SwitchPort srcPort =
582 new SwitchPort(new Dpid(srcInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700583 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800584
Ray Milkey269ffb92014-04-03 14:43:30 -0700585 DataPath dataPath = new DataPath();
586 dataPath.setSrcPort(srcPort);
587 dataPath.setDstPort(dstPort);
588 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800589
Ray Milkey269ffb92014-04-03 14:43:30 -0700590 // Create flow path matching condition(s): IPv4 Prefix
591 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700592 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700593 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
594 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
595 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300596
Ray Milkey269ffb92014-04-03 14:43:30 -0700597 /*
598 * Create the Flow Entry Action(s): dst-MAC rewrite action
599 */
600 FlowEntryActions flowEntryActions = new FlowEntryActions();
601 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
602 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
603 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
604 flowEntryActions.addAction(flowEntryAction1);
605 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800606
Ray Milkey269ffb92014-04-03 14:43:30 -0700607 // Flow Path installation, only to first hop switches
608 // TODO: Add the flow by using the new Path Intent framework
609 /*
610 if (flowManagerService.addFlow(flowPath) == null) {
611 log.error("Failed to install flow path to the first hop for " +
612 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
613 nextHopMacAddress);
614 }
615 else {
616 log.debug("Successfully installed flow path to the first hop " +
617 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
618 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800619
Ray Milkey269ffb92014-04-03 14:43:30 -0700620 pushedFlowIds.put(prefix, flowPath.flowId());
621 }
622 */
623 }
624 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700625
Jonathan Hart938a0152014-04-07 18:27:31 -0700626 public void processRibDelete(RibUpdate update) {
627 synchronized (this) {
628 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700629
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700630 //if (ptree.remove(prefix, update.getRibEntry())) {
631 // TODO check the change of logic here - remove doesn't check that the
632 // rib entry was what we expected (and we can't do this concurrently)
633 if (bgpRoutes.remove(prefix.toBinaryString())) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700634 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700635 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700636 * If no entry was removed, the <prefix, nexthop> wasn't there so
637 * it's probably already been removed and we don't need to do anything
638 */
Ray Milkey7531a342014-04-11 15:08:12 -0700639 executeDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart938a0152014-04-07 18:27:31 -0700640 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700641 }
642 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700643
Ray Milkey7531a342014-04-11 15:08:12 -0700644 private void executeDeletePrefix(Prefix prefix, RibEntry ribEntry) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700645 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700646
Ray Milkey269ffb92014-04-03 14:43:30 -0700647 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700648
Ray Milkey269ffb92014-04-03 14:43:30 -0700649 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
650 log.debug("Getting path for route with non-peer nexthop");
651 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700652
Ray Milkey269ffb92014-04-03 14:43:30 -0700653 if (path != null) {
654 //path could be null if we added to the Ptree but didn't push
655 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700656
Ray Milkey269ffb92014-04-03 14:43:30 -0700657 path.decrementUsers();
658 if (path.getUsers() <= 0 && !path.isPermanent()) {
659 deletePath(path);
660 pushedPaths.remove(path.getDstIpAddress());
661 }
662 }
663 }
664 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700665
Ray Milkey269ffb92014-04-03 14:43:30 -0700666 // TODO have not tested this module
667 private void deletePrefixFlows(Prefix prefix) {
668 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700669
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700670 //
671 // TODO: Delete the flow by using the new Path Intent framework
672 // NOTE: During the refactoring of the code below, if obtaining
673 // the values of the removed flowIds is needed, the first
674 // removeAll() statement should be replaced with the second removeAll()
675 // statement.
676 //
677 pushedFlowIds.removeAll(prefix);
678 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700679 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
680 for (FlowId flowId : flowIds) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700681 if (log.isTraceEnabled()) {
682 //Trace the flow status by flowPath in the switch before deleting it
683 log.trace("Pushing a DELETE flow mod to flowPath : {}",
684 flowManagerService.getFlow(flowId).toString());
685 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700686
Ray Milkey269ffb92014-04-03 14:43:30 -0700687 if( flowManagerService.deleteFlow(flowId))
688 {
689 log.debug("Successfully deleted FlowId: {}",flowId);
690 }
691 else
692 {
693 log.debug("Failed to delete FlowId: {}",flowId);
694 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700695 }
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700696 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700697 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700698
Ray Milkey269ffb92014-04-03 14:43:30 -0700699 // TODO need to record the path and then delete here
700 private void deletePath(Path path) {
701 log.debug("Deleting flows for path to {}",
702 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700703
Ray Milkey269ffb92014-04-03 14:43:30 -0700704 // TODO need update
705 /*for (PushedFlowMod pfm : path.getFlowMods()) {
706 if (log.isTraceEnabled()) {
707 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
708 new Object[] {HexString.toHexString(pfm.getDpid()),
709 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
710 });
711 }
pingping-linba5c52f2014-02-11 16:52:01 -0800712
Ray Milkey269ffb92014-04-03 14:43:30 -0700713 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
714 }*/
715 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700716
717
Ray Milkey269ffb92014-04-03 14:43:30 -0700718 //TODO test next-hop changes
719 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800720
Ray Milkey269ffb92014-04-03 14:43:30 -0700721 /**
722 * On startup, we need to calculate a full mesh of paths between all gateway
Ray Milkeyb41100a2014-04-10 10:42:15 -0700723 * switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700724 */
725 private void setupFullMesh() {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700726 // TODO: Fix the code below. Note that "deviceStorage" was removed.
727
728 /*
729
Ray Milkey269ffb92014-04-03 14:43:30 -0700730 //For each border router, calculate and install a path from every other
731 //border switch to said border router. However, don't install the entry
732 //in to the first hop switch, as we need to install an entry to rewrite
733 //for each prefix received. This will be done later when prefixes have
734 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700735
Ray Milkey269ffb92014-04-03 14:43:30 -0700736 for (BgpPeer peer : bgpPeers.values()) {
737 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700738
Ray Milkey269ffb92014-04-03 14:43:30 -0700739 //We know there's not already a Path here pushed, because this is
740 //called before all other routing
741 Path path = new Path(peerInterface, peer.getIpAddress());
742 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700743
Ray Milkey269ffb92014-04-03 14:43:30 -0700744 //See if we know the MAC address of the peer. If not we can't
745 //do anything until we learn it
Ray Milkey269ffb92014-04-03 14:43:30 -0700746 MACAddress macAddress = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700747 IDeviceObject nextHopDevice =
748 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800749
Ray Milkey269ffb92014-04-03 14:43:30 -0700750 if(nextHopDevice == null){
751 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
752 //Put in the pending paths list first
753 pathsWaitingOnArp.put(peer.getIpAddress(), path);
754 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
755 continue;
756 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700757
Ray Milkey269ffb92014-04-03 14:43:30 -0700758 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
pingping-linba5c52f2014-02-11 16:52:01 -0800759
Ray Milkey269ffb92014-04-03 14:43:30 -0700760 if (macAddress == null) {
761 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
762 //Put in the pending paths list first
763 pathsWaitingOnArp.put(peer.getIpAddress(), path);
764 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
765 continue;
766 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700767
Ray Milkey269ffb92014-04-03 14:43:30 -0700768 //If we know the MAC, lets go ahead and push the paths to this peer
769 calculateAndPushPath(path, macAddress);
770 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700771 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700772 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700773
Ray Milkey269ffb92014-04-03 14:43:30 -0700774 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
775 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700776
Ray Milkey269ffb92014-04-03 14:43:30 -0700777 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
778 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800779
Ray Milkey269ffb92014-04-03 14:43:30 -0700780 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800781
Ray Milkey269ffb92014-04-03 14:43:30 -0700782 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800783
Ray Milkey269ffb92014-04-03 14:43:30 -0700784 // Set flowPath FlowPathType and FlowPathUserState
785 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
786 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800787
Ray Milkey269ffb92014-04-03 14:43:30 -0700788 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
789 FlowPathFlags flowPathFlags = new FlowPathFlags();
790 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
791 flowPath.setFlowPathFlags(flowPathFlags);
792
793 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700794 SwitchPort dstPort =
795 new SwitchPort(new Dpid(dstInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700796 new PortNumber(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800797
Ray Milkey269ffb92014-04-03 14:43:30 -0700798 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800799
Ray Milkey269ffb92014-04-03 14:43:30 -0700800 if (dstInterface.equals(srcInterface)) {
801 continue;
802 }
pingping-linba5c52f2014-02-11 16:52:01 -0800803
Ray Milkey269ffb92014-04-03 14:43:30 -0700804 // Create flowPath FlowId
805 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800806
Ray Milkey269ffb92014-04-03 14:43:30 -0700807 // Create the DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700808 SwitchPort srcPort =
809 new SwitchPort(new Dpid(srcInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700810 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800811
Ray Milkey269ffb92014-04-03 14:43:30 -0700812 DataPath dataPath = new DataPath();
813 dataPath.setSrcPort(srcPort);
814 dataPath.setDstPort(dstPort);
815 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800816
Ray Milkey269ffb92014-04-03 14:43:30 -0700817 // Create the Flow Path Match condition(s)
818 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700819 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700820 flowEntryMatch.enableDstMac(dstMacAddress);
821 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800822
Ray Milkey269ffb92014-04-03 14:43:30 -0700823 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
824 // Shortest Path Flow, and is always the last action for the Flow Entries
825 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
826 // TODO: Add the flow by using the new Path Intent framework
827 /*
828 if (flowManagerService.addFlow(flowPath) == null) {
829 log.error("Failed to set up MAC based forwarding path to {}, {}",
830 path.getDstIpAddress().getHostAddress(),dstMacAddress);
831 }
832 else {
833 log.debug("Successfully set up MAC based forwarding path to {}, {}",
834 path.getDstIpAddress().getHostAddress(),dstMacAddress);
835 }
836 */
837 }
838 }
pingping-linba5c52f2014-02-11 16:52:01 -0800839
Komal Shah399a2922014-05-28 01:57:40 -0700840 @Override
841 public void beginRoutingNew() {
842 setupBgpPathsNew();
843
844 //setupFullMesh();
845
846 //Suppress link discovery on external-facing router ports
847
848 for (Interface intf : interfaces.values()) {
849 linkDiscoveryService.addToSuppressLLDPs(intf.getDpid(), intf.getPort());
850 }
851
852 bgpUpdatesExecutor.execute(new Runnable() {
853 @Override
854 public void run() {
855 doUpdatesThread();
856 }
857 });
858 }
859
Ray Milkey269ffb92014-04-03 14:43:30 -0700860 /**
Komal Shah399a2922014-05-28 01:57:40 -0700861 * Setup the Paths to the BGP Daemon.
862 *
863 * Run a loop for all of the bgpPeers
864 * Push flow from BGPd to the peer
865 * Push flow from peer to BGPd
866 * Parameters to pass to the intent are as follows:
867 * String id,
868 * long srcSwitch, long srcPort, long srcMac, int srcIP,
869 * long dstSwitch, long dstPort, long dstMac, int dstIP
870 */
871 private void setupBgpPathsNew() {
872 IntentOperationList operations = new IntentOperationList();
873 for (BgpPeer bgpPeer : bgpPeers.values()) {
874 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
875 //Inet4Address.
876 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
877 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
878 String fwdIntentId = callerId + ":" + controllerRegistryService.getNextUniqueId();
879 String bwdIntentId = callerId + ":" + controllerRegistryService.getNextUniqueId();
880 SwitchPort srcPort =
881 new SwitchPort(bgpdAttachmentPoint.dpid(),
882 bgpdAttachmentPoint.port());
883 SwitchPort dstPort =
884 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700885 new PortNumber(peerInterface.getSwitchPort().port()));
Komal Shah399a2922014-05-28 01:57:40 -0700886 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
887 srcPort.dpid().value(), srcPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, srcIP,
888 dstPort.dpid().value(), dstPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, dstIP);
889 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700890 dstPort.dpid().value(), dstPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, dstIP,
891 srcPort.dpid().value(), srcPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700892 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
893 operations.add(operator, fwdIntent);
894 operations.add(operator, bwdIntent);
895 }
896 pathRuntime.executeIntentOperations(operations);
897 }
898
899 /*
Jonathan Hart938a0152014-04-07 18:27:31 -0700900 * Proactively install all BGP traffic paths from BGP host attachment point
Ray Milkeyb41100a2014-04-10 10:42:15 -0700901 * in SDN network to all the virtual gateways to BGP peers in other networks.
Ray Milkey269ffb92014-04-03 14:43:30 -0700902 */
903 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200904
Ray Milkey269ffb92014-04-03 14:43:30 -0700905 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800906
Ray Milkey269ffb92014-04-03 14:43:30 -0700907 FlowPath flowPath = new FlowPath();
908 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800909
Ray Milkey269ffb92014-04-03 14:43:30 -0700910 // Set flowPath FlowPathType and FlowPathUserState
911 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
912 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800913
Ray Milkey269ffb92014-04-03 14:43:30 -0700914 // Install flow paths between BGPd and its peers
915 // There is no need to set the FlowPathFlags
916 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800917
Ray Milkey269ffb92014-04-03 14:43:30 -0700918 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Ray Milkey269ffb92014-04-03 14:43:30 -0700919 // Create the Flow Path Match condition(s)
920 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700921 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
pingping-linba5c52f2014-02-11 16:52:01 -0800922
Ray Milkey269ffb92014-04-03 14:43:30 -0700923 // Match both source address and dest address
924 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress() + "/32");
Komal Shah399a2922014-05-28 01:57:40 -0700925
Ray Milkey269ffb92014-04-03 14:43:30 -0700926 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800927
Ray Milkey269ffb92014-04-03 14:43:30 -0700928 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress().getHostAddress() + "/32");
929 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800930
Ray Milkey269ffb92014-04-03 14:43:30 -0700931 // Match TCP protocol
932 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800933
Ray Milkey269ffb92014-04-03 14:43:30 -0700934 // Match destination TCP port
935 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
936 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800937
Ray Milkey269ffb92014-04-03 14:43:30 -0700938 /**
939 * Create the DataPath: BGP -> BGP peer
940 */
941 // Flow path for src-TCP-port
942 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800943
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700944 SwitchPort srcPort =
945 new SwitchPort(bgpdAttachmentPoint.dpid(),
946 bgpdAttachmentPoint.port());
Ray Milkey269ffb92014-04-03 14:43:30 -0700947 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800948
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700949 SwitchPort dstPort =
950 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700951 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700952 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800953
Ray Milkey269ffb92014-04-03 14:43:30 -0700954 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800955
Ray Milkey269ffb92014-04-03 14:43:30 -0700956 // TODO: Add the flow by using the new Path Intent framework
957 /*
958 if (flowManagerService.addFlow(flowPath) == null) {
959 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
960 bgpPeer.getIpAddress().getHostAddress());
961 }
962 else {
963 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
964 bgpPeer.getIpAddress().getHostAddress());
965 }
966 */
pingping-linba5c52f2014-02-11 16:52:01 -0800967
Ray Milkey269ffb92014-04-03 14:43:30 -0700968 // Disable dst-TCP-port, and set src-TCP-port
969 flowEntryMatch.disableDstTcpUdpPort();
970 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
971 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800972
Ray Milkey269ffb92014-04-03 14:43:30 -0700973 // Create a new FlowId
974 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800975
Ray Milkey269ffb92014-04-03 14:43:30 -0700976 // TODO: Add the flow by using the new Path Intent framework
977 /*
978 if (flowManagerService.addFlow(flowPath) == null) {
979 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
980 bgpPeer.getIpAddress().getHostAddress());
981 }
982 else {
983 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
984 bgpPeer.getIpAddress().getHostAddress());
985 }
986 */
pingping-linba5c52f2014-02-11 16:52:01 -0800987
Ray Milkey269ffb92014-04-03 14:43:30 -0700988 /**
989 * Create the DataPath: BGP <-BGP peer
990 */
991 // Reversed BGP flow path for src-TCP-port
992 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800993
Ray Milkey2476cac2014-04-08 11:03:21 -0700994 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800995
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700996 SwitchPort reverseDstPort =
Komal Shah399a2922014-05-28 01:57:40 -0700997 new SwitchPort(bgpdAttachmentPoint.dpid(),
998 bgpdAttachmentPoint.port());
Ray Milkey2476cac2014-04-08 11:03:21 -0700999 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -08001000
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -07001001 SwitchPort reverseSrcPort =
Komal Shah399a2922014-05-28 01:57:40 -07001002 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -07001003 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey2476cac2014-04-08 11:03:21 -07001004 reverseDataPath.setSrcPort(reverseSrcPort);
1005 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001006
Jonathan Hart938a0152014-04-07 18:27:31 -07001007 // Reverse the dst IP and src IP addresses
Ray Milkey269ffb92014-04-03 14:43:30 -07001008 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
1009 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
1010 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001011
Ray Milkey269ffb92014-04-03 14:43:30 -07001012 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001013
Ray Milkey269ffb92014-04-03 14:43:30 -07001014 // TODO: Add the flow by using the new Path Intent framework
1015 /*
1016 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001017
Ray Milkey269ffb92014-04-03 14:43:30 -07001018 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
1019 bgpPeer.getIpAddress().getHostAddress());
1020 }
1021 else {
1022 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
1023 bgpPeer.getIpAddress().getHostAddress());
1024 }
1025 */
pingping-linba5c52f2014-02-11 16:52:01 -08001026
Ray Milkey269ffb92014-04-03 14:43:30 -07001027 // Reversed BGP flow path for dst-TCP-port
1028 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001029
Ray Milkey269ffb92014-04-03 14:43:30 -07001030 // Disable src-TCP-port, and set the dst-TCP-port
1031 flowEntryMatch.disableSrcTcpUdpPort();
1032 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
1033 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001034
Ray Milkey269ffb92014-04-03 14:43:30 -07001035 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001036
Ray Milkey269ffb92014-04-03 14:43:30 -07001037 // TODO: Add the flow by using the new Path Intent framework
1038 /*
1039 if (flowManagerService.addFlow(flowPath) == null) {
1040 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1041 bgpPeer.getIpAddress().getHostAddress());
1042 }
1043 else {
1044 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1045 bgpPeer.getIpAddress().getHostAddress());
1046 }
1047 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001048
Ray Milkey269ffb92014-04-03 14:43:30 -07001049 /**
1050 * ICMP paths between BGPd and its peers
1051 */
Jonathan Hart938a0152014-04-07 18:27:31 -07001052 // match ICMP protocol BGP <- Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001053 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001054
Ray Milkey269ffb92014-04-03 14:43:30 -07001055 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
1056 flowEntryMatch.disableSrcTcpUdpPort();
1057 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -08001058
Ray Milkey269ffb92014-04-03 14:43:30 -07001059 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001060
Ray Milkey2476cac2014-04-08 11:03:21 -07001061 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001062
Ray Milkey269ffb92014-04-03 14:43:30 -07001063 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001064
Ray Milkey269ffb92014-04-03 14:43:30 -07001065 // TODO: Add the flow by using the new Path Intent framework
1066 /*
1067 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001068
Ray Milkey269ffb92014-04-03 14:43:30 -07001069 log.error("Failed to set up ICMP path BGP <- Peer {}",
1070 bgpPeer.getIpAddress().getHostAddress());
1071 }
1072 else {
1073 log.debug("Successfully set up ICMP path BGP <- Peer {}",
1074 bgpPeer.getIpAddress().getHostAddress());
1075 }
1076 */
pingping-linba5c52f2014-02-11 16:52:01 -08001077
Jonathan Hart938a0152014-04-07 18:27:31 -07001078 // match ICMP protocol BGP -> Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001079 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001080
Ray Milkey269ffb92014-04-03 14:43:30 -07001081 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
1082 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
1083 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001084
Ray Milkey269ffb92014-04-03 14:43:30 -07001085 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001086
Ray Milkey269ffb92014-04-03 14:43:30 -07001087 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001088
Ray Milkey269ffb92014-04-03 14:43:30 -07001089 // TODO: Add the flow by using the new Path Intent framework
1090 /*
1091 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001092
Ray Milkey269ffb92014-04-03 14:43:30 -07001093 log.error("Failed to set up ICMP path BGP -> Peer {}",
1094 bgpPeer.getIpAddress().getHostAddress());
1095 }
1096 else {
1097 log.debug("Successfully set up ICMP path BGP -> Peer {}",
1098 bgpPeer.getIpAddress().getHostAddress());
1099 }
1100 */
1101 }
1102 }
pingping-linba5c52f2014-02-11 16:52:01 -08001103
Ray Milkey269ffb92014-04-03 14:43:30 -07001104 @Override
1105 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
1106 log.debug("Received ARP response: {} => {}",
1107 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001108
Ray Milkey269ffb92014-04-03 14:43:30 -07001109 /*
1110 * We synchronize on this to prevent changes to the ptree while we're pushing
1111 * flows to the switches. If the ptree changes, the ptree and switches
1112 * could get out of sync.
1113 */
1114 synchronized (this) {
1115 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001116
Ray Milkey269ffb92014-04-03 14:43:30 -07001117 if (path != null) {
1118 log.debug("Pushing path to {} at {} on {}", new Object[]{
1119 path.getDstIpAddress().getHostAddress(), macAddress,
1120 path.getDstInterface().getSwitchPort()});
Jonathan Hart938a0152014-04-07 18:27:31 -07001121 // These paths should always be to BGP peers. Paths to non-peers are
1122 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -07001123 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001124 // A path already got pushed to this endpoint while we were waiting
1125 // for ARP. We'll copy over the permanent attribute if it is set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -07001126 if (path.isPermanent()) {
1127 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1128 }
1129 } else {
1130 calculateAndPushPath(path, macAddress);
1131 pushedPaths.put(path.getDstIpAddress(), path);
1132 }
1133 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001134
Ray Milkey269ffb92014-04-03 14:43:30 -07001135 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001136
Ray Milkey269ffb92014-04-03 14:43:30 -07001137 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001138 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001139
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001140 RibEntry rib = bgpRoutes.getValueForExactKey(
1141 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -07001142 if (rib != null && rib.equals(update.getRibEntry())) {
1143 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1144 rib.getNextHop().getHostAddress());
Jonathan Hart938a0152014-04-07 18:27:31 -07001145 // We only push prefix flows if the prefix is still in the ptree
1146 // and the next hop is the same as our update. The prefix could
1147 // have been removed while we were waiting for the ARP, or the
1148 // next hop could have changed.
Ray Milkey7531a342014-04-11 15:08:12 -07001149 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -07001150 } else {
1151 log.debug("Received ARP response, but {},{} is no longer in ptree",
1152 update.getPrefix(), update.getRibEntry());
1153 }
1154 }
1155 }
1156 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001157
Jonathan Hart938a0152014-04-07 18:27:31 -07001158 // TODO wait the priority module of the flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001159 private void setupArpFlows() {
1160 OFMatch match = new OFMatch();
1161 match.setDataLayerType(Ethernet.TYPE_ARP);
1162 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001163
Ray Milkey269ffb92014-04-03 14:43:30 -07001164 OFFlowMod fm = new OFFlowMod();
1165 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001166
Ray Milkey269ffb92014-04-03 14:43:30 -07001167 OFActionOutput action = new OFActionOutput();
1168 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1169 action.setMaxLength((short) 0xffff);
1170 List<OFAction> actions = new ArrayList<OFAction>(1);
1171 actions.add(action);
1172 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001173
Ray Milkey269ffb92014-04-03 14:43:30 -07001174 fm.setIdleTimeout((short) 0)
1175 .setHardTimeout((short) 0)
1176 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1177 .setCookie(0)
1178 .setCommand(OFFlowMod.OFPFC_ADD)
1179 .setPriority(ARP_PRIORITY)
1180 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001181
Ray Milkey269ffb92014-04-03 14:43:30 -07001182 for (String strdpid : switches) {
1183 flowCache.write(HexString.toLong(strdpid), fm);
1184 }
1185 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001186
Jonathan Hart938a0152014-04-07 18:27:31 -07001187 // TODO need update, waiting for the priority feature from flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001188 private void setupDefaultDropFlows() {
1189 OFFlowMod fm = new OFFlowMod();
1190 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -07001191 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001192
Ray Milkey269ffb92014-04-03 14:43:30 -07001193 fm.setIdleTimeout((short) 0)
1194 .setHardTimeout((short) 0)
1195 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1196 .setCookie(0)
1197 .setCommand(OFFlowMod.OFPFC_ADD)
1198 .setPriority((short) 0)
1199 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001200
Ray Milkey269ffb92014-04-03 14:43:30 -07001201 OFFlowMod fmLLDP;
1202 OFFlowMod fmBDDP;
1203 try {
1204 fmLLDP = fm.clone();
1205 fmBDDP = fm.clone();
1206 } catch (CloneNotSupportedException e1) {
1207 log.error("Error cloning flow mod", e1);
1208 return;
1209 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001210
Ray Milkey269ffb92014-04-03 14:43:30 -07001211 OFMatch matchLLDP = new OFMatch();
1212 matchLLDP.setDataLayerType((short) 0x88cc);
1213 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1214 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001215
Ray Milkey269ffb92014-04-03 14:43:30 -07001216 OFMatch matchBDDP = new OFMatch();
1217 matchBDDP.setDataLayerType((short) 0x8942);
1218 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1219 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001220
Ray Milkey269ffb92014-04-03 14:43:30 -07001221 OFActionOutput action = new OFActionOutput();
1222 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1223 action.setMaxLength((short) 0xffff);
1224 List<OFAction> actions = new ArrayList<OFAction>(1);
1225 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001226
Ray Milkey269ffb92014-04-03 14:43:30 -07001227 fmLLDP.setActions(actions);
1228 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001229
Ray Milkey269ffb92014-04-03 14:43:30 -07001230 fmLLDP.setPriority(ARP_PRIORITY);
1231 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1232 fmBDDP.setPriority(ARP_PRIORITY);
1233 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001234
Ray Milkey269ffb92014-04-03 14:43:30 -07001235 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1236 flowModList.add(fm);
1237 flowModList.add(fmLLDP);
1238 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001239
Ray Milkey269ffb92014-04-03 14:43:30 -07001240 for (String strdpid : switches) {
1241 flowCache.write(HexString.toLong(strdpid), flowModList);
1242 }
1243 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001244
Ray Milkey269ffb92014-04-03 14:43:30 -07001245 private void beginRouting() {
1246 log.debug("Topology is now ready, beginning routing function");
1247 // TODO: Fix for the new Topology Network Graph
1248 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001249
Ray Milkey269ffb92014-04-03 14:43:30 -07001250 // Wait Pavlin's API. We need the following functions.
1251 /*setupArpFlows();
1252 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001253
Ray Milkey269ffb92014-04-03 14:43:30 -07001254 setupBgpPaths();
1255 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001256
Ray Milkey269ffb92014-04-03 14:43:30 -07001257 //Suppress link discovery on external-facing router ports
1258 for (Interface intf : interfaces.values()) {
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -07001259 linkDiscoveryService.addToSuppressLLDPs(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001260 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001261
Ray Milkey269ffb92014-04-03 14:43:30 -07001262 bgpUpdatesExecutor.execute(new Runnable() {
1263 @Override
1264 public void run() {
1265 doUpdatesThread();
1266 }
1267 });
1268 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001269
Jonathan Hart938a0152014-04-07 18:27:31 -07001270 // Before inserting the paths for BGP traffic, we should check whether
1271 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001272 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001273 // TODO: Fix the code below after topoSwitchSerice was removed
1274 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001275 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001276
Ray Milkey269ffb92014-04-03 14:43:30 -07001277 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1278 getActiveSwitches().iterator();
1279 while(activeSwitches.hasNext())
1280 {
1281 ISwitchObject switchObject = activeSwitches.next();
1282 if (switchObject.getDPID().equals(dpid)) {
1283 break;
1284 }
1285 if(activeSwitches.hasNext() == false) {
1286 log.debug("Not all switches are here yet");
1287 return;
1288 }
1289 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001290 }
1291 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001292 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001293 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001294
Jonathan Hart938a0152014-04-07 18:27:31 -07001295 // Actually we only need to go half way round to verify full mesh connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001296 private void checkTopologyReady() {
1297 for (Interface dstInterface : interfaces.values()) {
1298 for (Interface srcInterface : interfaces.values()) {
1299 if (dstInterface.equals(srcInterface)) {
1300 continue;
1301 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001302
Ray Milkey269ffb92014-04-03 14:43:30 -07001303 // TODO: Fix for the new Topology Network Graph
1304 /*
1305 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1306 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001307
Ray Milkey269ffb92014-04-03 14:43:30 -07001308 if (shortestPath == null){
1309 log.debug("Shortest path between {} and {} not found",
1310 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1311 return;
1312 }
1313 */
1314 }
1315 }
1316 topologyReady = true;
1317 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001318
Ray Milkey269ffb92014-04-03 14:43:30 -07001319 private void checkStatus() {
1320 if (!switchesConnected) {
1321 checkSwitchesConnected();
1322 }
1323 boolean oldTopologyReadyStatus = topologyReady;
1324 if (switchesConnected && !topologyReady) {
1325 checkTopologyReady();
1326 }
1327 if (!oldTopologyReadyStatus && topologyReady) {
1328 beginRouting();
1329 }
1330 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001331
Ray Milkey269ffb92014-04-03 14:43:30 -07001332 private void doUpdatesThread() {
1333 boolean interrupted = false;
1334 try {
1335 while (true) {
1336 try {
1337 RibUpdate update = ribUpdates.take();
1338 switch (update.getOperation()) {
1339 case UPDATE:
1340 if (validateUpdate(update)) {
1341 processRibAdd(update);
1342 } else {
1343 log.debug("Rib UPDATE out of order: {} via {}",
1344 update.getPrefix(), update.getRibEntry().getNextHop());
1345 }
1346 break;
1347 case DELETE:
1348 if (validateUpdate(update)) {
1349 processRibDelete(update);
1350 } else {
1351 log.debug("Rib DELETE out of order: {} via {}",
1352 update.getPrefix(), update.getRibEntry().getNextHop());
1353 }
1354 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -07001355 default:
1356 log.error("Unknown operation {}", update.getOperation());
1357 break;
Ray Milkey269ffb92014-04-03 14:43:30 -07001358 }
1359 } catch (InterruptedException e) {
1360 log.debug("Interrupted while taking from updates queue", e);
1361 interrupted = true;
1362 } catch (Exception e) {
1363 log.debug("exception", e);
1364 }
1365 }
1366 } finally {
1367 if (interrupted) {
1368 Thread.currentThread().interrupt();
1369 }
1370 }
1371 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001372
Ray Milkey269ffb92014-04-03 14:43:30 -07001373 private boolean validateUpdate(RibUpdate update) {
1374 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001375 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
1376 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001377
Ray Milkey269ffb92014-04-03 14:43:30 -07001378 //If there is no existing entry we must assume this is the most recent
1379 //update. However this might not always be the case as we might have a
1380 //POST then DELETE reordering.
1381 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1382 if (oldEntry == null) {
1383 return true;
1384 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001385
Ray Milkey269ffb92014-04-03 14:43:30 -07001386 // This handles the case where routes are gathered in the initial
1387 // request because they don't have sequence number info
1388 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1389 return true;
1390 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001391
Ray Milkey269ffb92014-04-03 14:43:30 -07001392 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1393 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001394 }
Ray Milkey4985f212014-04-10 16:57:05 -07001395
1396 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
1397 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -07001398 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001399
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001400 private Interface longestInterfacePrefixMatch(InetAddress address) {
1401 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
1402 Prefix.MAX_PREFIX_LENGTH);
1403 Iterator<Interface> it =
1404 interfaceRoutes.getValuesForKeysPrefixing(
1405 prefixToSearchFor.toBinaryString()).iterator();
1406 Interface intf = null;
1407 // Find the last prefix, which will be the longest prefix
1408 while (it.hasNext()) {
1409 intf = it.next();
1410 }
1411
1412 return intf;
1413 }
1414
Ray Milkey269ffb92014-04-03 14:43:30 -07001415 // The code below should be reimplemented after removal of Floodlight's
1416 // ITopologyService API. It should be implemented on top of network graph
1417 // notifications. (It was pretty hacky anyway...)
1418 /*
1419 @Override
1420 public void topologyChanged() {
1421 if (topologyReady) {
1422 return;
1423 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001424
Ray Milkey269ffb92014-04-03 14:43:30 -07001425 boolean refreshNeeded = false;
1426 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1427 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1428 //We don't need to recalculate anything for just link updates
1429 //They happen very frequently
1430 refreshNeeded = true;
1431 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001432
Ray Milkey269ffb92014-04-03 14:43:30 -07001433 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001434
Ray Milkey269ffb92014-04-03 14:43:30 -07001435 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1436 synchronized (linkUpdates) {
1437 linkUpdates.add(ldu);
1438 }
1439 }
1440 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001441
Ray Milkey269ffb92014-04-03 14:43:30 -07001442 if (refreshNeeded && !topologyReady){
1443 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1444 }
1445 }
1446 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001447
Ray Milkey269ffb92014-04-03 14:43:30 -07001448 @Override
1449 public void addedSwitch(IOFSwitch sw) {
1450 if (!topologyReady) {
1451 sw.clearAllFlowMods();
1452 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001453
Ray Milkey269ffb92014-04-03 14:43:30 -07001454 flowCache.switchConnected(sw);
1455 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001456
Ray Milkey269ffb92014-04-03 14:43:30 -07001457 @Override
1458 public void removedSwitch(IOFSwitch sw) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001459 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001460 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001461
Ray Milkey269ffb92014-04-03 14:43:30 -07001462 @Override
1463 public void switchPortChanged(Long switchId) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001464 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001465 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001466
Ray Milkey269ffb92014-04-03 14:43:30 -07001467 @Override
1468 public String getName() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001469 return "sdnip";
Ray Milkey269ffb92014-04-03 14:43:30 -07001470 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001471
Ray Milkey269ffb92014-04-03 14:43:30 -07001472 /*
1473 * IConfigInfoService methods
1474 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001475
Ray Milkey269ffb92014-04-03 14:43:30 -07001476 @Override
1477 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001478 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001479 return (intf != null && intf.getIpAddress().equals(address));
1480 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001481
Ray Milkey269ffb92014-04-03 14:43:30 -07001482 @Override
1483 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001484 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001485 return (intf != null && !intf.getIpAddress().equals(address));
1486 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001487
Ray Milkey269ffb92014-04-03 14:43:30 -07001488 @Override
1489 public boolean fromExternalNetwork(long inDpid, short inPort) {
1490 for (Interface intf : interfaces.values()) {
1491 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1492 return true;
1493 }
1494 }
1495 return false;
1496 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001497
Ray Milkey269ffb92014-04-03 14:43:30 -07001498 @Override
1499 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001500 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -07001501 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001502
Ray Milkey269ffb92014-04-03 14:43:30 -07001503 @Override
1504 public boolean hasLayer3Configuration() {
1505 return !interfaces.isEmpty();
1506 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001507
Ray Milkey269ffb92014-04-03 14:43:30 -07001508 @Override
1509 public MACAddress getRouterMacAddress() {
1510 return bgpdMacAddress;
1511 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001512
Ray Milkey269ffb92014-04-03 14:43:30 -07001513 @Override
1514 public short getVlan() {
1515 return vlan;
1516 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001517}