blob: b8d8e878dbd2da22b530155fa417df0679e4f2f7 [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();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700219 interfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700220 for (Interface intf : config.getInterfaces()) {
221 interfaces.put(intf.getName(), intf);
222 }
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700223 bgpPeers = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700224 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();
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -0700234 } catch (JsonParseException | JsonMappingException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700235 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 (IOException e) {
238 log.error("Error reading 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 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700241
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700242 // Populate the interface Patricia Tree
Ray Milkey269ffb92014-04-03 14:43:30 -0700243 for (Interface intf : interfaces.values()) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700244 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
245 intf.getPrefixLength());
246 interfaceRoutes.put(prefix.toBinaryString(), intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700247 }
248 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700249
Ray Milkey269ffb92014-04-03 14:43:30 -0700250 @Override
251 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
252 Collection<Class<? extends IFloodlightService>> l
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700253 = new ArrayList<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700254 l.add(ISdnIpService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700255 l.add(IConfigInfoService.class);
256 return l;
257 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700258
Ray Milkey269ffb92014-04-03 14:43:30 -0700259 @Override
260 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
261 Map<Class<? extends IFloodlightService>, IFloodlightService> m
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700262 = new HashMap<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700263 m.put(ISdnIpService.class, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700264 m.put(IConfigInfoService.class, this);
265 return m;
266 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800267
Ray Milkey269ffb92014-04-03 14:43:30 -0700268 @Override
269 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
270 Collection<Class<? extends IFloodlightService>> l
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700271 = new ArrayList<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700272 l.add(IFloodlightProviderService.class);
273 l.add(IRestApiService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700274 l.add(IControllerRegistryService.class);
275 l.add(IPathCalcRuntimeService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700276 return l;
277 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700278
Ray Milkey269ffb92014-04-03 14:43:30 -0700279 @Override
280 public void init(FloodlightModuleContext context)
281 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700282
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700283 bgpRoutes = new ConcurrentInvertedRadixTree<>(
284 new DefaultByteArrayNodeFactory());
285 interfaceRoutes = new ConcurrentInvertedRadixTree<>(
286 new DefaultByteArrayNodeFactory());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700287
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700288 ribUpdates = new LinkedBlockingQueue<>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700289
Ray Milkey269ffb92014-04-03 14:43:30 -0700290 // Register floodlight provider and REST handler.
291 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
292 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
293 restApi = context.getServiceImpl(IRestApiService.class);
294 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800295
Komal Shah399a2922014-05-28 01:57:40 -0700296 controllerRegistryService = context.getServiceImpl(IControllerRegistryService.class);
297 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700298 linkUpdates = new ArrayList<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700299 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
300 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700301
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700302 pathsWaitingOnArp = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
304 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700305
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700306 pushedPaths = new HashMap<>();
307 prefixToPath = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700308// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700309 pushedFlowIds = HashMultimap.create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700310
Ray Milkey269ffb92014-04-03 14:43:30 -0700311 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700312
Ray Milkey269ffb92014-04-03 14:43:30 -0700313 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
314 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700315
Jonathan Hart938a0152014-04-07 18:27:31 -0700316 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700317 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
318 if (bgpdRestIp == null) {
319 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700320 throw new ConfigurationRuntimeException(
321 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700322 } else {
323 log.info("BgpdRestIp set to {}", bgpdRestIp);
324 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700325
Ray Milkey269ffb92014-04-03 14:43:30 -0700326 routerId = context.getConfigParams(this).get("RouterId");
327 if (routerId == null) {
328 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700329 throw new ConfigurationRuntimeException(
330 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700331 } else {
332 log.info("RouterId set to {}", routerId);
333 }
pingping-linba5c52f2014-02-11 16:52:01 -0800334
Ray Milkey269ffb92014-04-03 14:43:30 -0700335 String configFilenameParameter = context.getConfigParams(this).get("configfile");
336 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700337 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700338 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700339 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700340
Ray Milkey5df613b2014-04-15 10:50:56 -0700341 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700342 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700343
Ray Milkey269ffb92014-04-03 14:43:30 -0700344 @Override
345 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700346 restApi.addRestletRoutable(new SdnIpWebRoutable());
Komal Shah399a2922014-05-28 01:57:40 -0700347 restApi.addRestletRoutable(new SdnIpWebRoutableNew());
Ray Milkey269ffb92014-04-03 14:43:30 -0700348 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800349
Jonathan Hart938a0152014-04-07 18:27:31 -0700350 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700351 retrieveRib();
352 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800353
Ray Milkey269ffb92014-04-03 14:43:30 -0700354 @Override
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700355 public RadixTree<RibEntry> getPtree() {
356 return bgpRoutes;
Ray Milkey269ffb92014-04-03 14:43:30 -0700357 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700358
Ray Milkey269ffb92014-04-03 14:43:30 -0700359 @Override
360 public void clearPtree() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700361 log.warn("Clear table operation not supported");
Ray Milkey269ffb92014-04-03 14:43:30 -0700362 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700363
Ray Milkey269ffb92014-04-03 14:43:30 -0700364 @Override
Jonathan Hart31e15f12014-04-10 10:33:00 -0700365 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700366 return bgpdRestIp;
367 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700368
Ray Milkey269ffb92014-04-03 14:43:30 -0700369 @Override
370 public String getRouterId() {
371 return routerId;
372 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700373
Ray Milkey269ffb92014-04-03 14:43:30 -0700374 private void retrieveRib() {
375 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
376 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700377
Jonathan Hart938a0152014-04-07 18:27:31 -0700378 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700379 return;
380 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700381
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700382 try {
383 response = response.replaceAll("\"", "'");
384 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
385 JSONArray ribArray = jsonObj.getJSONArray("rib");
386 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700387
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700388 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700389
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700390 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700391
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700392 for (int j = 0; j < size; j++) {
393 JSONObject ribEntry = ribArray.getJSONObject(j);
394 String prefix = ribEntry.getString("prefix");
395 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700396
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700397 // Insert each rib entry into the local rib
398 String[] substring = prefix.split("/");
399 String prefix1 = substring[0];
400 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700401
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700402 Prefix p;
403 try {
404 p = new Prefix(prefix1, Integer.parseInt(mask1));
405 } catch (NumberFormatException e) {
406 log.warn("Wrong mask format in RIB JSON: {}", mask1);
407 continue;
408 } catch (IllegalArgumentException e1) {
409 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
410 continue;
411 }
412
413 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
414
415 try {
416 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
417 } catch (InterruptedException e) {
418 log.debug("Interrupted while pushing onto update queue");
419 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700420 }
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700421 } catch (JSONException e) {
422 // TODO don't parse JSON manually
423 log.error("Error parsing inital route table JSON:", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700424 }
425 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700426
Ray Milkey269ffb92014-04-03 14:43:30 -0700427 @Override
428 public void newRibUpdate(RibUpdate update) {
429 try {
430 ribUpdates.put(update);
431 } catch (InterruptedException e) {
432 log.debug("Interrupted while putting on ribUpdates queue", e);
433 Thread.currentThread().interrupt();
434 }
435 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700436
Jonathan Hart938a0152014-04-07 18:27:31 -0700437 public void processRibAdd(RibUpdate update) {
438 synchronized (this) {
439 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700440
Jonathan Hart938a0152014-04-07 18:27:31 -0700441 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700442
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700443 RibEntry rib = bgpRoutes.put(prefix.toBinaryString(), update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700444
Jonathan Hart938a0152014-04-07 18:27:31 -0700445 if (rib != null && !rib.equals(update.getRibEntry())) {
446 // There was an existing nexthop for this prefix. This update supersedes that,
447 // so we need to remove the old flows for this prefix from the switches
Ray Milkey7531a342014-04-11 15:08:12 -0700448 executeDeletePrefix(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700449 }
Ray Milkey5d406012014-04-08 14:44:41 -0700450
Jonathan Hart938a0152014-04-07 18:27:31 -0700451 if (update.getRibEntry().getNextHop().equals(
452 InetAddresses.forString("0.0.0.0"))) {
453 // Route originated by SDN domain
454 // We don't handle these at the moment
455 log.debug("Own route {} to {}", prefix,
456 update.getRibEntry().getNextHop().getHostAddress());
457 return;
458 }
Ray Milkey5d406012014-04-08 14:44:41 -0700459
Ray Milkey7531a342014-04-11 15:08:12 -0700460 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700461 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700462 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700463
Ray Milkey7531a342014-04-11 15:08:12 -0700464 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700465 // TODO: Fix the code below. Note that "deviceStorage" was removed.
466
467 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700468 Prefix prefix = update.getPrefix();
469 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700470
Ray Milkey269ffb92014-04-03 14:43:30 -0700471 InetAddress dstIpAddress = rib.getNextHop();
472 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800473
Ray Milkey269ffb92014-04-03 14:43:30 -0700474 // See if we know the MAC address of the next hop
475 // 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 -0700476 IDeviceObject nextHopDevice =
477 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700478
Ray Milkey269ffb92014-04-03 14:43:30 -0700479 if (nextHopDevice == null){
480 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
481 prefixesWaitingOnArp.put(dstIpAddress,
482 new RibUpdate(Operation.UPDATE, prefix, rib));
483 proxyArp.sendArpRequest(dstIpAddress, this, true);
484 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800485
Ray Milkey269ffb92014-04-03 14:43:30 -0700486 }
487 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700488
Ray Milkey269ffb92014-04-03 14:43:30 -0700489 // Find the attachment point (egress interface) of the next hop
490 Interface egressInterface = null;
491 if (bgpPeers.containsKey(dstIpAddress)) {
492 //Route to a peer
493 log.debug("Route to peer {}", dstIpAddress);
494 BgpPeer peer = bgpPeers.get(dstIpAddress);
495 egressInterface = interfaces.get(peer.getInterfaceName());
496 } else {
497 //Route to non-peer
498 log.debug("Route to non-peer {}", dstIpAddress);
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700499 egressInterface = interfacePtree.match(
Ray Milkey269ffb92014-04-03 14:43:30 -0700500 new Prefix(dstIpAddress.getAddress(), 32));
501 if (egressInterface == null) {
502 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
503 return;
504 }
505 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700506
Ray Milkey269ffb92014-04-03 14:43:30 -0700507 if (nextHopMacAddress == null) {
508 prefixesWaitingOnArp.put(dstIpAddress,
509 new RibUpdate(Operation.UPDATE, prefix, rib));
510 proxyArp.sendArpRequest(dstIpAddress, this, true);
511 return;
512 } else {
513 if (!bgpPeers.containsKey(dstIpAddress)) {
514 //If the prefix is for a non-peer we need to ensure there's a path,
515 //and push one if there isn't.
516 Path path = pushedPaths.get(dstIpAddress);
517 if (path == null) {
518 path = new Path(egressInterface, dstIpAddress);
519 calculateAndPushPath(path, nextHopMacAddress);
520 pushedPaths.put(dstIpAddress, path);
521 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700522
Ray Milkey269ffb92014-04-03 14:43:30 -0700523 path.incrementUsers();
524 prefixToPath.put(prefix, path);
525 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700526
Ray Milkey269ffb92014-04-03 14:43:30 -0700527 //For all prefixes we need to add the first-hop mac-rewriting flows
528 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
529 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700530 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700531 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700532
Ray Milkey269ffb92014-04-03 14:43:30 -0700533 /**
534 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
Ray Milkeyb41100a2014-04-10 10:42:15 -0700535 * to all other border switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700536 */
537 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
538 MACAddress nextHopMacAddress) {
539 log.debug("Adding flows for prefix {}, next hop mac {}",
540 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700541
Ray Milkey269ffb92014-04-03 14:43:30 -0700542 FlowPath flowPath = new FlowPath();
543 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700544
Ray Milkey269ffb92014-04-03 14:43:30 -0700545 // Set flowPath FlowPathType and FlowPathUserState
546 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
547 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800548
Ray Milkey269ffb92014-04-03 14:43:30 -0700549 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
550 // only to the first-host switches
551 FlowPathFlags flowPathFlags = new FlowPathFlags();
552 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
553 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800554
Ray Milkey269ffb92014-04-03 14:43:30 -0700555 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700556 SwitchPort dstPort =
557 new SwitchPort(new Dpid(egressInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700558 new PortNumber(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800559
Ray Milkey269ffb92014-04-03 14:43:30 -0700560 // We only need one flow mod per switch, so pick one interface on each switch
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700561 Map<Long, Interface> srcInterfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700562 for (Interface intf : interfaces.values()) {
563 if (!srcInterfaces.containsKey(intf.getDpid())
564 && !intf.equals(egressInterface)) {
565 srcInterfaces.put(intf.getDpid(), intf);
566 }
567 }
568 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800569
Ray Milkey269ffb92014-04-03 14:43:30 -0700570 if (egressInterface.equals(srcInterface)) {
571 continue;
572 }
pingping-linba5c52f2014-02-11 16:52:01 -0800573
Ray Milkey269ffb92014-04-03 14:43:30 -0700574 // Create flowPath FlowId
575 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800576
Ray Milkey269ffb92014-04-03 14:43:30 -0700577 // Create DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700578 SwitchPort srcPort =
579 new SwitchPort(new Dpid(srcInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700580 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800581
Ray Milkey269ffb92014-04-03 14:43:30 -0700582 DataPath dataPath = new DataPath();
583 dataPath.setSrcPort(srcPort);
584 dataPath.setDstPort(dstPort);
585 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800586
Ray Milkey269ffb92014-04-03 14:43:30 -0700587 // Create flow path matching condition(s): IPv4 Prefix
588 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700589 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700590 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
591 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
592 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300593
Ray Milkey269ffb92014-04-03 14:43:30 -0700594 /*
595 * Create the Flow Entry Action(s): dst-MAC rewrite action
596 */
597 FlowEntryActions flowEntryActions = new FlowEntryActions();
598 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
599 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
600 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
601 flowEntryActions.addAction(flowEntryAction1);
602 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800603
Ray Milkey269ffb92014-04-03 14:43:30 -0700604 // Flow Path installation, only to first hop switches
605 // TODO: Add the flow by using the new Path Intent framework
606 /*
607 if (flowManagerService.addFlow(flowPath) == null) {
608 log.error("Failed to install flow path to the first hop for " +
609 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
610 nextHopMacAddress);
611 }
612 else {
613 log.debug("Successfully installed flow path to the first hop " +
614 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
615 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800616
Ray Milkey269ffb92014-04-03 14:43:30 -0700617 pushedFlowIds.put(prefix, flowPath.flowId());
618 }
619 */
620 }
621 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700622
Jonathan Hart938a0152014-04-07 18:27:31 -0700623 public void processRibDelete(RibUpdate update) {
624 synchronized (this) {
625 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700626
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700627 //if (ptree.remove(prefix, update.getRibEntry())) {
628 // TODO check the change of logic here - remove doesn't check that the
629 // rib entry was what we expected (and we can't do this concurrently)
630 if (bgpRoutes.remove(prefix.toBinaryString())) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700631 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700632 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700633 * If no entry was removed, the <prefix, nexthop> wasn't there so
634 * it's probably already been removed and we don't need to do anything
635 */
Ray Milkey7531a342014-04-11 15:08:12 -0700636 executeDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart938a0152014-04-07 18:27:31 -0700637 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700638 }
639 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700640
Ray Milkey7531a342014-04-11 15:08:12 -0700641 private void executeDeletePrefix(Prefix prefix, RibEntry ribEntry) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700642 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700643
Ray Milkey269ffb92014-04-03 14:43:30 -0700644 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700645
Ray Milkey269ffb92014-04-03 14:43:30 -0700646 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
647 log.debug("Getting path for route with non-peer nexthop");
648 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700649
Ray Milkey269ffb92014-04-03 14:43:30 -0700650 if (path != null) {
651 //path could be null if we added to the Ptree but didn't push
652 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700653
Ray Milkey269ffb92014-04-03 14:43:30 -0700654 path.decrementUsers();
655 if (path.getUsers() <= 0 && !path.isPermanent()) {
656 deletePath(path);
657 pushedPaths.remove(path.getDstIpAddress());
658 }
659 }
660 }
661 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700662
Ray Milkey269ffb92014-04-03 14:43:30 -0700663 // TODO have not tested this module
664 private void deletePrefixFlows(Prefix prefix) {
665 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700666
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700667 //
668 // TODO: Delete the flow by using the new Path Intent framework
669 // NOTE: During the refactoring of the code below, if obtaining
670 // the values of the removed flowIds is needed, the first
671 // removeAll() statement should be replaced with the second removeAll()
672 // statement.
673 //
674 pushedFlowIds.removeAll(prefix);
675 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700676 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
677 for (FlowId flowId : flowIds) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700678 if (log.isTraceEnabled()) {
679 //Trace the flow status by flowPath in the switch before deleting it
680 log.trace("Pushing a DELETE flow mod to flowPath : {}",
681 flowManagerService.getFlow(flowId).toString());
682 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700683
Ray Milkey269ffb92014-04-03 14:43:30 -0700684 if( flowManagerService.deleteFlow(flowId))
685 {
686 log.debug("Successfully deleted FlowId: {}",flowId);
687 }
688 else
689 {
690 log.debug("Failed to delete FlowId: {}",flowId);
691 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700692 }
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700693 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700694 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700695
Ray Milkey269ffb92014-04-03 14:43:30 -0700696 // TODO need to record the path and then delete here
697 private void deletePath(Path path) {
698 log.debug("Deleting flows for path to {}",
699 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700700
Ray Milkey269ffb92014-04-03 14:43:30 -0700701 // TODO need update
702 /*for (PushedFlowMod pfm : path.getFlowMods()) {
703 if (log.isTraceEnabled()) {
704 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
705 new Object[] {HexString.toHexString(pfm.getDpid()),
706 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
707 });
708 }
pingping-linba5c52f2014-02-11 16:52:01 -0800709
Ray Milkey269ffb92014-04-03 14:43:30 -0700710 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
711 }*/
712 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700713
714
Ray Milkey269ffb92014-04-03 14:43:30 -0700715 //TODO test next-hop changes
716 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800717
Ray Milkey269ffb92014-04-03 14:43:30 -0700718 /**
719 * On startup, we need to calculate a full mesh of paths between all gateway
Ray Milkeyb41100a2014-04-10 10:42:15 -0700720 * switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700721 */
722 private void setupFullMesh() {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700723 // TODO: Fix the code below. Note that "deviceStorage" was removed.
724
725 /*
726
Ray Milkey269ffb92014-04-03 14:43:30 -0700727 //For each border router, calculate and install a path from every other
728 //border switch to said border router. However, don't install the entry
729 //in to the first hop switch, as we need to install an entry to rewrite
730 //for each prefix received. This will be done later when prefixes have
731 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700732
Ray Milkey269ffb92014-04-03 14:43:30 -0700733 for (BgpPeer peer : bgpPeers.values()) {
734 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700735
Ray Milkey269ffb92014-04-03 14:43:30 -0700736 //We know there's not already a Path here pushed, because this is
737 //called before all other routing
738 Path path = new Path(peerInterface, peer.getIpAddress());
739 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700740
Ray Milkey269ffb92014-04-03 14:43:30 -0700741 //See if we know the MAC address of the peer. If not we can't
742 //do anything until we learn it
Ray Milkey269ffb92014-04-03 14:43:30 -0700743 MACAddress macAddress = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700744 IDeviceObject nextHopDevice =
745 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800746
Ray Milkey269ffb92014-04-03 14:43:30 -0700747 if(nextHopDevice == null){
748 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
749 //Put in the pending paths list first
750 pathsWaitingOnArp.put(peer.getIpAddress(), path);
751 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
752 continue;
753 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700754
Ray Milkey269ffb92014-04-03 14:43:30 -0700755 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
pingping-linba5c52f2014-02-11 16:52:01 -0800756
Ray Milkey269ffb92014-04-03 14:43:30 -0700757 if (macAddress == null) {
758 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
759 //Put in the pending paths list first
760 pathsWaitingOnArp.put(peer.getIpAddress(), path);
761 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
762 continue;
763 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700764
Ray Milkey269ffb92014-04-03 14:43:30 -0700765 //If we know the MAC, lets go ahead and push the paths to this peer
766 calculateAndPushPath(path, macAddress);
767 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700768 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700769 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700770
Ray Milkey269ffb92014-04-03 14:43:30 -0700771 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
772 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700773
Ray Milkey269ffb92014-04-03 14:43:30 -0700774 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
775 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800776
Ray Milkey269ffb92014-04-03 14:43:30 -0700777 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800778
Ray Milkey269ffb92014-04-03 14:43:30 -0700779 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800780
Ray Milkey269ffb92014-04-03 14:43:30 -0700781 // Set flowPath FlowPathType and FlowPathUserState
782 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
783 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800784
Ray Milkey269ffb92014-04-03 14:43:30 -0700785 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
786 FlowPathFlags flowPathFlags = new FlowPathFlags();
787 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
788 flowPath.setFlowPathFlags(flowPathFlags);
789
790 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700791 SwitchPort dstPort =
792 new SwitchPort(new Dpid(dstInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700793 new PortNumber(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800794
Ray Milkey269ffb92014-04-03 14:43:30 -0700795 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800796
Ray Milkey269ffb92014-04-03 14:43:30 -0700797 if (dstInterface.equals(srcInterface)) {
798 continue;
799 }
pingping-linba5c52f2014-02-11 16:52:01 -0800800
Ray Milkey269ffb92014-04-03 14:43:30 -0700801 // Create flowPath FlowId
802 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800803
Ray Milkey269ffb92014-04-03 14:43:30 -0700804 // Create the DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700805 SwitchPort srcPort =
806 new SwitchPort(new Dpid(srcInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700807 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800808
Ray Milkey269ffb92014-04-03 14:43:30 -0700809 DataPath dataPath = new DataPath();
810 dataPath.setSrcPort(srcPort);
811 dataPath.setDstPort(dstPort);
812 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800813
Ray Milkey269ffb92014-04-03 14:43:30 -0700814 // Create the Flow Path Match condition(s)
815 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700816 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700817 flowEntryMatch.enableDstMac(dstMacAddress);
818 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800819
Ray Milkey269ffb92014-04-03 14:43:30 -0700820 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
821 // Shortest Path Flow, and is always the last action for the Flow Entries
822 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
823 // TODO: Add the flow by using the new Path Intent framework
824 /*
825 if (flowManagerService.addFlow(flowPath) == null) {
826 log.error("Failed to set up MAC based forwarding path to {}, {}",
827 path.getDstIpAddress().getHostAddress(),dstMacAddress);
828 }
829 else {
830 log.debug("Successfully set up MAC based forwarding path to {}, {}",
831 path.getDstIpAddress().getHostAddress(),dstMacAddress);
832 }
833 */
834 }
835 }
pingping-linba5c52f2014-02-11 16:52:01 -0800836
Komal Shah399a2922014-05-28 01:57:40 -0700837 @Override
838 public void beginRoutingNew() {
839 setupBgpPathsNew();
840
841 //setupFullMesh();
842
843 //Suppress link discovery on external-facing router ports
844
845 for (Interface intf : interfaces.values()) {
846 linkDiscoveryService.addToSuppressLLDPs(intf.getDpid(), intf.getPort());
847 }
848
849 bgpUpdatesExecutor.execute(new Runnable() {
850 @Override
851 public void run() {
852 doUpdatesThread();
853 }
854 });
855 }
856
Ray Milkey269ffb92014-04-03 14:43:30 -0700857 /**
Komal Shah399a2922014-05-28 01:57:40 -0700858 * Setup the Paths to the BGP Daemon.
859 *
860 * Run a loop for all of the bgpPeers
861 * Push flow from BGPd to the peer
862 * Push flow from peer to BGPd
863 * Parameters to pass to the intent are as follows:
864 * String id,
865 * long srcSwitch, long srcPort, long srcMac, int srcIP,
866 * long dstSwitch, long dstPort, long dstMac, int dstIP
867 */
868 private void setupBgpPathsNew() {
869 IntentOperationList operations = new IntentOperationList();
870 for (BgpPeer bgpPeer : bgpPeers.values()) {
871 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
872 //Inet4Address.
873 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
874 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
875 String fwdIntentId = callerId + ":" + controllerRegistryService.getNextUniqueId();
876 String bwdIntentId = callerId + ":" + controllerRegistryService.getNextUniqueId();
877 SwitchPort srcPort =
878 new SwitchPort(bgpdAttachmentPoint.dpid(),
879 bgpdAttachmentPoint.port());
880 SwitchPort dstPort =
881 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700882 new PortNumber(peerInterface.getSwitchPort().port()));
Komal Shah399a2922014-05-28 01:57:40 -0700883 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
884 srcPort.dpid().value(), srcPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, srcIP,
885 dstPort.dpid().value(), dstPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, dstIP);
886 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700887 dstPort.dpid().value(), dstPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, dstIP,
888 srcPort.dpid().value(), srcPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700889 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
890 operations.add(operator, fwdIntent);
891 operations.add(operator, bwdIntent);
892 }
893 pathRuntime.executeIntentOperations(operations);
894 }
895
896 /*
Jonathan Hart938a0152014-04-07 18:27:31 -0700897 * Proactively install all BGP traffic paths from BGP host attachment point
Ray Milkeyb41100a2014-04-10 10:42:15 -0700898 * in SDN network to all the virtual gateways to BGP peers in other networks.
Ray Milkey269ffb92014-04-03 14:43:30 -0700899 */
900 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200901
Ray Milkey269ffb92014-04-03 14:43:30 -0700902 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800903
Ray Milkey269ffb92014-04-03 14:43:30 -0700904 FlowPath flowPath = new FlowPath();
905 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800906
Ray Milkey269ffb92014-04-03 14:43:30 -0700907 // Set flowPath FlowPathType and FlowPathUserState
908 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
909 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800910
Ray Milkey269ffb92014-04-03 14:43:30 -0700911 // Install flow paths between BGPd and its peers
912 // There is no need to set the FlowPathFlags
913 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800914
Ray Milkey269ffb92014-04-03 14:43:30 -0700915 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Ray Milkey269ffb92014-04-03 14:43:30 -0700916 // Create the Flow Path Match condition(s)
917 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700918 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
pingping-linba5c52f2014-02-11 16:52:01 -0800919
Ray Milkey269ffb92014-04-03 14:43:30 -0700920 // Match both source address and dest address
921 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress() + "/32");
Komal Shah399a2922014-05-28 01:57:40 -0700922
Ray Milkey269ffb92014-04-03 14:43:30 -0700923 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800924
Ray Milkey269ffb92014-04-03 14:43:30 -0700925 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress().getHostAddress() + "/32");
926 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800927
Ray Milkey269ffb92014-04-03 14:43:30 -0700928 // Match TCP protocol
929 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800930
Ray Milkey269ffb92014-04-03 14:43:30 -0700931 // Match destination TCP port
932 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
933 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800934
Ray Milkey269ffb92014-04-03 14:43:30 -0700935 /**
936 * Create the DataPath: BGP -> BGP peer
937 */
938 // Flow path for src-TCP-port
939 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800940
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700941 SwitchPort srcPort =
942 new SwitchPort(bgpdAttachmentPoint.dpid(),
943 bgpdAttachmentPoint.port());
Ray Milkey269ffb92014-04-03 14:43:30 -0700944 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800945
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700946 SwitchPort dstPort =
947 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700948 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700949 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800950
Ray Milkey269ffb92014-04-03 14:43:30 -0700951 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800952
Ray Milkey269ffb92014-04-03 14:43:30 -0700953 // TODO: Add the flow by using the new Path Intent framework
954 /*
955 if (flowManagerService.addFlow(flowPath) == null) {
956 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
957 bgpPeer.getIpAddress().getHostAddress());
958 }
959 else {
960 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
961 bgpPeer.getIpAddress().getHostAddress());
962 }
963 */
pingping-linba5c52f2014-02-11 16:52:01 -0800964
Ray Milkey269ffb92014-04-03 14:43:30 -0700965 // Disable dst-TCP-port, and set src-TCP-port
966 flowEntryMatch.disableDstTcpUdpPort();
967 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
968 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800969
Ray Milkey269ffb92014-04-03 14:43:30 -0700970 // Create a new FlowId
971 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800972
Ray Milkey269ffb92014-04-03 14:43:30 -0700973 // TODO: Add the flow by using the new Path Intent framework
974 /*
975 if (flowManagerService.addFlow(flowPath) == null) {
976 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
977 bgpPeer.getIpAddress().getHostAddress());
978 }
979 else {
980 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
981 bgpPeer.getIpAddress().getHostAddress());
982 }
983 */
pingping-linba5c52f2014-02-11 16:52:01 -0800984
Ray Milkey269ffb92014-04-03 14:43:30 -0700985 /**
986 * Create the DataPath: BGP <-BGP peer
987 */
988 // Reversed BGP flow path for src-TCP-port
989 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800990
Ray Milkey2476cac2014-04-08 11:03:21 -0700991 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800992
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700993 SwitchPort reverseDstPort =
Komal Shah399a2922014-05-28 01:57:40 -0700994 new SwitchPort(bgpdAttachmentPoint.dpid(),
995 bgpdAttachmentPoint.port());
Ray Milkey2476cac2014-04-08 11:03:21 -0700996 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800997
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700998 SwitchPort reverseSrcPort =
Komal Shah399a2922014-05-28 01:57:40 -0700999 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -07001000 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey2476cac2014-04-08 11:03:21 -07001001 reverseDataPath.setSrcPort(reverseSrcPort);
1002 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001003
Jonathan Hart938a0152014-04-07 18:27:31 -07001004 // Reverse the dst IP and src IP addresses
Ray Milkey269ffb92014-04-03 14:43:30 -07001005 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
1006 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
1007 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001008
Ray Milkey269ffb92014-04-03 14:43:30 -07001009 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001010
Ray Milkey269ffb92014-04-03 14:43:30 -07001011 // TODO: Add the flow by using the new Path Intent framework
1012 /*
1013 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001014
Ray Milkey269ffb92014-04-03 14:43:30 -07001015 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
1016 bgpPeer.getIpAddress().getHostAddress());
1017 }
1018 else {
1019 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
1020 bgpPeer.getIpAddress().getHostAddress());
1021 }
1022 */
pingping-linba5c52f2014-02-11 16:52:01 -08001023
Ray Milkey269ffb92014-04-03 14:43:30 -07001024 // Reversed BGP flow path for dst-TCP-port
1025 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001026
Ray Milkey269ffb92014-04-03 14:43:30 -07001027 // Disable src-TCP-port, and set the dst-TCP-port
1028 flowEntryMatch.disableSrcTcpUdpPort();
1029 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
1030 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001031
Ray Milkey269ffb92014-04-03 14:43:30 -07001032 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001033
Ray Milkey269ffb92014-04-03 14:43:30 -07001034 // TODO: Add the flow by using the new Path Intent framework
1035 /*
1036 if (flowManagerService.addFlow(flowPath) == null) {
1037 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1038 bgpPeer.getIpAddress().getHostAddress());
1039 }
1040 else {
1041 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1042 bgpPeer.getIpAddress().getHostAddress());
1043 }
1044 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001045
Ray Milkey269ffb92014-04-03 14:43:30 -07001046 /**
1047 * ICMP paths between BGPd and its peers
1048 */
Jonathan Hart938a0152014-04-07 18:27:31 -07001049 // match ICMP protocol BGP <- Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001050 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001051
Ray Milkey269ffb92014-04-03 14:43:30 -07001052 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
1053 flowEntryMatch.disableSrcTcpUdpPort();
1054 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -08001055
Ray Milkey269ffb92014-04-03 14:43:30 -07001056 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001057
Ray Milkey2476cac2014-04-08 11:03:21 -07001058 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001059
Ray Milkey269ffb92014-04-03 14:43:30 -07001060 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001061
Ray Milkey269ffb92014-04-03 14:43:30 -07001062 // TODO: Add the flow by using the new Path Intent framework
1063 /*
1064 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001065
Ray Milkey269ffb92014-04-03 14:43:30 -07001066 log.error("Failed to set up ICMP path BGP <- Peer {}",
1067 bgpPeer.getIpAddress().getHostAddress());
1068 }
1069 else {
1070 log.debug("Successfully set up ICMP path BGP <- Peer {}",
1071 bgpPeer.getIpAddress().getHostAddress());
1072 }
1073 */
pingping-linba5c52f2014-02-11 16:52:01 -08001074
Jonathan Hart938a0152014-04-07 18:27:31 -07001075 // match ICMP protocol BGP -> Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001076 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001077
Ray Milkey269ffb92014-04-03 14:43:30 -07001078 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
1079 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
1080 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001081
Ray Milkey269ffb92014-04-03 14:43:30 -07001082 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001083
Ray Milkey269ffb92014-04-03 14:43:30 -07001084 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001085
Ray Milkey269ffb92014-04-03 14:43:30 -07001086 // TODO: Add the flow by using the new Path Intent framework
1087 /*
1088 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001089
Ray Milkey269ffb92014-04-03 14:43:30 -07001090 log.error("Failed to set up ICMP path BGP -> Peer {}",
1091 bgpPeer.getIpAddress().getHostAddress());
1092 }
1093 else {
1094 log.debug("Successfully set up ICMP path BGP -> Peer {}",
1095 bgpPeer.getIpAddress().getHostAddress());
1096 }
1097 */
1098 }
1099 }
pingping-linba5c52f2014-02-11 16:52:01 -08001100
Ray Milkey269ffb92014-04-03 14:43:30 -07001101 @Override
1102 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
1103 log.debug("Received ARP response: {} => {}",
1104 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001105
Ray Milkey269ffb92014-04-03 14:43:30 -07001106 /*
1107 * We synchronize on this to prevent changes to the ptree while we're pushing
1108 * flows to the switches. If the ptree changes, the ptree and switches
1109 * could get out of sync.
1110 */
1111 synchronized (this) {
1112 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001113
Ray Milkey269ffb92014-04-03 14:43:30 -07001114 if (path != null) {
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -07001115 log.debug("Pushing path to {} at {} on {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001116 path.getDstIpAddress().getHostAddress(), macAddress,
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -07001117 path.getDstInterface().getSwitchPort());
Jonathan Hart938a0152014-04-07 18:27:31 -07001118 // These paths should always be to BGP peers. Paths to non-peers are
1119 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -07001120 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001121 // A path already got pushed to this endpoint while we were waiting
1122 // for ARP. We'll copy over the permanent attribute if it is set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -07001123 if (path.isPermanent()) {
1124 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1125 }
1126 } else {
1127 calculateAndPushPath(path, macAddress);
1128 pushedPaths.put(path.getDstIpAddress(), path);
1129 }
1130 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001131
Ray Milkey269ffb92014-04-03 14:43:30 -07001132 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001133
Ray Milkey269ffb92014-04-03 14:43:30 -07001134 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001135 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001136
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001137 RibEntry rib = bgpRoutes.getValueForExactKey(
1138 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -07001139 if (rib != null && rib.equals(update.getRibEntry())) {
1140 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1141 rib.getNextHop().getHostAddress());
Jonathan Hart938a0152014-04-07 18:27:31 -07001142 // We only push prefix flows if the prefix is still in the ptree
1143 // and the next hop is the same as our update. The prefix could
1144 // have been removed while we were waiting for the ARP, or the
1145 // next hop could have changed.
Ray Milkey7531a342014-04-11 15:08:12 -07001146 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -07001147 } else {
1148 log.debug("Received ARP response, but {},{} is no longer in ptree",
1149 update.getPrefix(), update.getRibEntry());
1150 }
1151 }
1152 }
1153 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001154
Jonathan Hart938a0152014-04-07 18:27:31 -07001155 // TODO wait the priority module of the flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001156 private void setupArpFlows() {
1157 OFMatch match = new OFMatch();
1158 match.setDataLayerType(Ethernet.TYPE_ARP);
1159 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001160
Ray Milkey269ffb92014-04-03 14:43:30 -07001161 OFFlowMod fm = new OFFlowMod();
1162 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001163
Ray Milkey269ffb92014-04-03 14:43:30 -07001164 OFActionOutput action = new OFActionOutput();
1165 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1166 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001167 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -07001168 actions.add(action);
1169 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001170
Ray Milkey269ffb92014-04-03 14:43:30 -07001171 fm.setIdleTimeout((short) 0)
1172 .setHardTimeout((short) 0)
1173 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1174 .setCookie(0)
1175 .setCommand(OFFlowMod.OFPFC_ADD)
1176 .setPriority(ARP_PRIORITY)
1177 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001178
Ray Milkey269ffb92014-04-03 14:43:30 -07001179 for (String strdpid : switches) {
1180 flowCache.write(HexString.toLong(strdpid), fm);
1181 }
1182 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001183
Jonathan Hart938a0152014-04-07 18:27:31 -07001184 // TODO need update, waiting for the priority feature from flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001185 private void setupDefaultDropFlows() {
1186 OFFlowMod fm = new OFFlowMod();
1187 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -07001188 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001189
Ray Milkey269ffb92014-04-03 14:43:30 -07001190 fm.setIdleTimeout((short) 0)
1191 .setHardTimeout((short) 0)
1192 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1193 .setCookie(0)
1194 .setCommand(OFFlowMod.OFPFC_ADD)
1195 .setPriority((short) 0)
1196 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001197
Ray Milkey269ffb92014-04-03 14:43:30 -07001198 OFFlowMod fmLLDP;
1199 OFFlowMod fmBDDP;
1200 try {
1201 fmLLDP = fm.clone();
1202 fmBDDP = fm.clone();
1203 } catch (CloneNotSupportedException e1) {
1204 log.error("Error cloning flow mod", e1);
1205 return;
1206 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001207
Ray Milkey269ffb92014-04-03 14:43:30 -07001208 OFMatch matchLLDP = new OFMatch();
1209 matchLLDP.setDataLayerType((short) 0x88cc);
1210 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1211 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001212
Ray Milkey269ffb92014-04-03 14:43:30 -07001213 OFMatch matchBDDP = new OFMatch();
1214 matchBDDP.setDataLayerType((short) 0x8942);
1215 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1216 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001217
Ray Milkey269ffb92014-04-03 14:43:30 -07001218 OFActionOutput action = new OFActionOutput();
1219 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1220 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001221 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -07001222 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001223
Ray Milkey269ffb92014-04-03 14:43:30 -07001224 fmLLDP.setActions(actions);
1225 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001226
Ray Milkey269ffb92014-04-03 14:43:30 -07001227 fmLLDP.setPriority(ARP_PRIORITY);
1228 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1229 fmBDDP.setPriority(ARP_PRIORITY);
1230 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001231
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001232 List<OFFlowMod> flowModList = new ArrayList<>(3);
Ray Milkey269ffb92014-04-03 14:43:30 -07001233 flowModList.add(fm);
1234 flowModList.add(fmLLDP);
1235 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001236
Ray Milkey269ffb92014-04-03 14:43:30 -07001237 for (String strdpid : switches) {
1238 flowCache.write(HexString.toLong(strdpid), flowModList);
1239 }
1240 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001241
Ray Milkey269ffb92014-04-03 14:43:30 -07001242 private void beginRouting() {
1243 log.debug("Topology is now ready, beginning routing function");
1244 // TODO: Fix for the new Topology Network Graph
1245 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001246
Ray Milkey269ffb92014-04-03 14:43:30 -07001247 // Wait Pavlin's API. We need the following functions.
1248 /*setupArpFlows();
1249 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001250
Ray Milkey269ffb92014-04-03 14:43:30 -07001251 setupBgpPaths();
1252 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001253
Ray Milkey269ffb92014-04-03 14:43:30 -07001254 //Suppress link discovery on external-facing router ports
1255 for (Interface intf : interfaces.values()) {
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -07001256 linkDiscoveryService.addToSuppressLLDPs(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001257 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001258
Ray Milkey269ffb92014-04-03 14:43:30 -07001259 bgpUpdatesExecutor.execute(new Runnable() {
1260 @Override
1261 public void run() {
1262 doUpdatesThread();
1263 }
1264 });
1265 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001266
Jonathan Hart938a0152014-04-07 18:27:31 -07001267 // Before inserting the paths for BGP traffic, we should check whether
1268 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001269 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001270 // TODO: Fix the code below after topoSwitchSerice was removed
1271 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001272 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001273
Ray Milkey269ffb92014-04-03 14:43:30 -07001274 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1275 getActiveSwitches().iterator();
1276 while(activeSwitches.hasNext())
1277 {
1278 ISwitchObject switchObject = activeSwitches.next();
1279 if (switchObject.getDPID().equals(dpid)) {
1280 break;
1281 }
1282 if(activeSwitches.hasNext() == false) {
1283 log.debug("Not all switches are here yet");
1284 return;
1285 }
1286 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001287 }
1288 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001289 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001290 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001291
Jonathan Hart938a0152014-04-07 18:27:31 -07001292 // Actually we only need to go half way round to verify full mesh connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001293 private void checkTopologyReady() {
1294 for (Interface dstInterface : interfaces.values()) {
1295 for (Interface srcInterface : interfaces.values()) {
1296 if (dstInterface.equals(srcInterface)) {
1297 continue;
1298 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001299
Ray Milkey269ffb92014-04-03 14:43:30 -07001300 // TODO: Fix for the new Topology Network Graph
1301 /*
1302 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1303 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001304
Ray Milkey269ffb92014-04-03 14:43:30 -07001305 if (shortestPath == null){
1306 log.debug("Shortest path between {} and {} not found",
1307 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1308 return;
1309 }
1310 */
1311 }
1312 }
1313 topologyReady = true;
1314 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001315
Ray Milkey269ffb92014-04-03 14:43:30 -07001316 private void checkStatus() {
1317 if (!switchesConnected) {
1318 checkSwitchesConnected();
1319 }
1320 boolean oldTopologyReadyStatus = topologyReady;
1321 if (switchesConnected && !topologyReady) {
1322 checkTopologyReady();
1323 }
1324 if (!oldTopologyReadyStatus && topologyReady) {
1325 beginRouting();
1326 }
1327 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001328
Ray Milkey269ffb92014-04-03 14:43:30 -07001329 private void doUpdatesThread() {
1330 boolean interrupted = false;
1331 try {
1332 while (true) {
1333 try {
1334 RibUpdate update = ribUpdates.take();
1335 switch (update.getOperation()) {
1336 case UPDATE:
1337 if (validateUpdate(update)) {
1338 processRibAdd(update);
1339 } else {
1340 log.debug("Rib UPDATE out of order: {} via {}",
1341 update.getPrefix(), update.getRibEntry().getNextHop());
1342 }
1343 break;
1344 case DELETE:
1345 if (validateUpdate(update)) {
1346 processRibDelete(update);
1347 } else {
1348 log.debug("Rib DELETE out of order: {} via {}",
1349 update.getPrefix(), update.getRibEntry().getNextHop());
1350 }
1351 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -07001352 default:
1353 log.error("Unknown operation {}", update.getOperation());
1354 break;
Ray Milkey269ffb92014-04-03 14:43:30 -07001355 }
1356 } catch (InterruptedException e) {
1357 log.debug("Interrupted while taking from updates queue", e);
1358 interrupted = true;
1359 } catch (Exception e) {
1360 log.debug("exception", e);
1361 }
1362 }
1363 } finally {
1364 if (interrupted) {
1365 Thread.currentThread().interrupt();
1366 }
1367 }
1368 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001369
Ray Milkey269ffb92014-04-03 14:43:30 -07001370 private boolean validateUpdate(RibUpdate update) {
1371 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001372 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
1373 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001374
Ray Milkey269ffb92014-04-03 14:43:30 -07001375 //If there is no existing entry we must assume this is the most recent
1376 //update. However this might not always be the case as we might have a
1377 //POST then DELETE reordering.
1378 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1379 if (oldEntry == null) {
1380 return true;
1381 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001382
Ray Milkey269ffb92014-04-03 14:43:30 -07001383 // This handles the case where routes are gathered in the initial
1384 // request because they don't have sequence number info
1385 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1386 return true;
1387 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001388
Ray Milkey269ffb92014-04-03 14:43:30 -07001389 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1390 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001391 }
Ray Milkey4985f212014-04-10 16:57:05 -07001392
1393 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
1394 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -07001395 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001396
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001397 private Interface longestInterfacePrefixMatch(InetAddress address) {
1398 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
1399 Prefix.MAX_PREFIX_LENGTH);
1400 Iterator<Interface> it =
1401 interfaceRoutes.getValuesForKeysPrefixing(
1402 prefixToSearchFor.toBinaryString()).iterator();
1403 Interface intf = null;
1404 // Find the last prefix, which will be the longest prefix
1405 while (it.hasNext()) {
1406 intf = it.next();
1407 }
1408
1409 return intf;
1410 }
1411
Ray Milkey269ffb92014-04-03 14:43:30 -07001412 // The code below should be reimplemented after removal of Floodlight's
1413 // ITopologyService API. It should be implemented on top of network graph
1414 // notifications. (It was pretty hacky anyway...)
1415 /*
1416 @Override
1417 public void topologyChanged() {
1418 if (topologyReady) {
1419 return;
1420 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001421
Ray Milkey269ffb92014-04-03 14:43:30 -07001422 boolean refreshNeeded = false;
1423 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1424 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1425 //We don't need to recalculate anything for just link updates
1426 //They happen very frequently
1427 refreshNeeded = true;
1428 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001429
Ray Milkey269ffb92014-04-03 14:43:30 -07001430 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001431
Ray Milkey269ffb92014-04-03 14:43:30 -07001432 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1433 synchronized (linkUpdates) {
1434 linkUpdates.add(ldu);
1435 }
1436 }
1437 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001438
Ray Milkey269ffb92014-04-03 14:43:30 -07001439 if (refreshNeeded && !topologyReady){
1440 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1441 }
1442 }
1443 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001444
Ray Milkey269ffb92014-04-03 14:43:30 -07001445 @Override
1446 public void addedSwitch(IOFSwitch sw) {
1447 if (!topologyReady) {
1448 sw.clearAllFlowMods();
1449 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001450
Ray Milkey269ffb92014-04-03 14:43:30 -07001451 flowCache.switchConnected(sw);
1452 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001453
Ray Milkey269ffb92014-04-03 14:43:30 -07001454 @Override
1455 public void removedSwitch(IOFSwitch sw) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001456 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001457 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001458
Ray Milkey269ffb92014-04-03 14:43:30 -07001459 @Override
1460 public void switchPortChanged(Long switchId) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001461 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001462 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001463
Ray Milkey269ffb92014-04-03 14:43:30 -07001464 @Override
1465 public String getName() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001466 return "sdnip";
Ray Milkey269ffb92014-04-03 14:43:30 -07001467 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001468
Ray Milkey269ffb92014-04-03 14:43:30 -07001469 /*
1470 * IConfigInfoService methods
1471 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001472
Ray Milkey269ffb92014-04-03 14:43:30 -07001473 @Override
1474 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001475 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001476 return (intf != null && intf.getIpAddress().equals(address));
1477 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001478
Ray Milkey269ffb92014-04-03 14:43:30 -07001479 @Override
1480 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001481 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001482 return (intf != null && !intf.getIpAddress().equals(address));
1483 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001484
Ray Milkey269ffb92014-04-03 14:43:30 -07001485 @Override
1486 public boolean fromExternalNetwork(long inDpid, short inPort) {
1487 for (Interface intf : interfaces.values()) {
1488 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1489 return true;
1490 }
1491 }
1492 return false;
1493 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001494
Ray Milkey269ffb92014-04-03 14:43:30 -07001495 @Override
1496 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001497 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -07001498 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001499
Ray Milkey269ffb92014-04-03 14:43:30 -07001500 @Override
1501 public boolean hasLayer3Configuration() {
1502 return !interfaces.isEmpty();
1503 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001504
Ray Milkey269ffb92014-04-03 14:43:30 -07001505 @Override
1506 public MACAddress getRouterMacAddress() {
1507 return bgpdMacAddress;
1508 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001509
Ray Milkey269ffb92014-04-03 14:43:30 -07001510 @Override
1511 public short getVlan() {
1512 return vlan;
1513 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001514}