blob: f4bf28d42e1947e27f0b6f4ec624384078c40198 [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;
pingping-lina2cbfad2013-03-07 08:39:21 +080017
Jonathan Hart61ba9372013-05-19 20:10:29 -070018import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070019import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart64c0b202013-08-20 15:45:07 +120020import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080021import net.floodlightcontroller.core.module.FloodlightModuleContext;
22import net.floodlightcontroller.core.module.FloodlightModuleException;
23import net.floodlightcontroller.core.module.IFloodlightModule;
24import net.floodlightcontroller.core.module.IFloodlightService;
pingping-lina2cbfad2013-03-07 08:39:21 +080025import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120026import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0961fe82014-04-03 09:56:25 -070027import net.onrc.onos.apps.proxyarp.IArpRequester;
28import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart8f6dc092014-04-18 15:56:43 -070029import net.onrc.onos.apps.sdnip.RibUpdate.Operation;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070030import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutable;
Komal Shah399a2922014-05-28 01:57:40 -070031import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutableNew;
32import net.onrc.onos.core.intent.IntentOperation;
33import net.onrc.onos.core.intent.IntentOperationList;
34import net.onrc.onos.core.intent.ShortestPathIntent;
35import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
Jonathan Harta99ec672014-04-03 11:30:34 -070036import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070037import net.onrc.onos.core.main.config.IConfigInfoService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070038import net.onrc.onos.core.packet.Ethernet;
39import net.onrc.onos.core.packet.IPv4;
Komal Shah399a2922014-05-28 01:57:40 -070040import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart23701d12014-04-03 10:45:48 -070041import net.onrc.onos.core.util.CallerId;
42import net.onrc.onos.core.util.DataPath;
43import net.onrc.onos.core.util.Dpid;
44import net.onrc.onos.core.util.FlowEntryAction;
45import net.onrc.onos.core.util.FlowEntryActions;
46import net.onrc.onos.core.util.FlowEntryMatch;
47import net.onrc.onos.core.util.FlowId;
48import net.onrc.onos.core.util.FlowPath;
49import net.onrc.onos.core.util.FlowPathFlags;
50import net.onrc.onos.core.util.FlowPathType;
51import net.onrc.onos.core.util.FlowPathUserState;
52import net.onrc.onos.core.util.IPv4Net;
Yuta HIGUCHIfb564502014-06-16 21:29:00 -070053import net.onrc.onos.core.util.PortNumber;
Jonathan Hart23701d12014-04-03 10:45:48 -070054import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080055import net.sf.json.JSONArray;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070056import net.sf.json.JSONException;
pingping-line2a09ca2013-03-23 09:33:58 +080057import net.sf.json.JSONObject;
58import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080059
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070060import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120061import org.codehaus.jackson.JsonParseException;
62import org.codehaus.jackson.map.JsonMappingException;
63import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070064import org.openflow.protocol.OFFlowMod;
65import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070066import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120067import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070068import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070069import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120070import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080071import org.slf4j.Logger;
72import org.slf4j.LoggerFactory;
73
Jonathan Hart4dfc3652013-08-02 20:22:36 +120074import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120075import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120076import com.google.common.collect.Multimaps;
77import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120078import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120079import com.google.common.util.concurrent.ThreadFactoryBuilder;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070080import com.googlecode.concurrenttrees.radix.RadixTree;
81import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
82import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
83import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120084
Jonathan Hart8f6dc092014-04-18 15:56:43 -070085public class SdnIp implements IFloodlightModule, ISdnIpService,
Ray Milkey269ffb92014-04-03 14:43:30 -070086 IArpRequester,
87 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070088
Jonathan Hart8f6dc092014-04-18 15:56:43 -070089 private static final Logger log = LoggerFactory.getLogger(SdnIp.class);
Sho SHIMIZU9ec39822014-07-10 17:15:12 -070090 private final CallerId callerId = new CallerId("SDNIP");
pingping-lina2cbfad2013-03-07 08:39:21 +080091
Ray Milkey269ffb92014-04-03 14:43:30 -070092 private IFloodlightProviderService floodlightProvider;
93 private ILinkDiscoveryService linkDiscoveryService;
94 private IRestApiService restApi;
95 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070096
Jonathan Hartf6978ce2014-06-23 11:20:04 -070097 private InvertedRadixTree<RibEntry> bgpRoutes;
98 private InvertedRadixTree<Interface> interfaceRoutes;
99
Ray Milkey269ffb92014-04-03 14:43:30 -0700100 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700101
Ray Milkey269ffb92014-04-03 14:43:30 -0700102 private String bgpdRestIp;
103 private String routerId;
Ray Milkey5df613b2014-04-15 10:50:56 -0700104 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
105 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700106
Komal Shah399a2922014-05-28 01:57:40 -0700107 /* ShortestPath Intent Variables */
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700108 private final String caller = "SdnIp";
Komal Shah399a2922014-05-28 01:57:40 -0700109 private IControllerRegistryService controllerRegistryService;
110 private IPathCalcRuntimeService pathRuntime;
111 /* Shortest Intent Path Variables */
112
Ray Milkey2476cac2014-04-08 11:03:21 -0700113 private static final short ARP_PRIORITY = 20;
Ray Milkey5d406012014-04-08 14:44:41 -0700114
Jonathan Hart938a0152014-04-07 18:27:31 -0700115 // The fields below are unused after the move to FlowManager.
116 // Remove them if no longer needed.
117 /*
118 // We need to identify our flows somehow, in lieu of an OS-wide mechanism
119 // to hand out cookie IDs to prevent conflicts.
120 private static final long APP_COOKIE = 0xa0000000000000L;
121 // Cookie for flows that do L2 forwarding within SDN domain to egress routers
122 private static final long L2_FWD_COOKIE = APP_COOKIE + 1;
123 // Cookie for flows in ingress switches that rewrite the MAC address
124 private static final long MAC_RW_COOKIE = APP_COOKIE + 2;
125 // Cookie for flows that setup BGP paths
126 private static final long BGP_COOKIE = APP_COOKIE + 3;
127 // Forwarding uses priority 0, and the mac rewrite entries in ingress switches
128 // need to be higher priority than this otherwise the rewrite may not get done
129 private static final short SDNIP_PRIORITY = 10;
130 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700131
Ray Milkey2476cac2014-04-08 11:03:21 -0700132 private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700133
Jonathan Hart938a0152014-04-07 18:27:31 -0700134 private static final int TOPO_DETECTION_WAIT = 2; // seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700135
Jonathan Hart938a0152014-04-07 18:27:31 -0700136 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700137 private List<String> switches;
138 private Map<String, Interface> interfaces;
139 private Map<InetAddress, BgpPeer> bgpPeers;
140 private SwitchPort bgpdAttachmentPoint;
141 private MACAddress bgpdMacAddress;
142 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700143
Jonathan Hart938a0152014-04-07 18:27:31 -0700144 // True when all switches have connected
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 private volatile boolean switchesConnected = false;
Jonathan Hart938a0152014-04-07 18:27:31 -0700146 // True when we have a full mesh of shortest paths between gateways
Ray Milkey269ffb92014-04-03 14:43:30 -0700147 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200148
Jonathan Hart284e70f2014-07-05 12:32:51 -0700149 //private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700150
Ray Milkey269ffb92014-04-03 14:43:30 -0700151 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700152
Ray Milkey269ffb92014-04-03 14:43:30 -0700153 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700154
Ray Milkey269ffb92014-04-03 14:43:30 -0700155 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700156
Ray Milkey269ffb92014-04-03 14:43:30 -0700157 private Map<InetAddress, Path> pushedPaths;
158 private Map<Prefix, Path> prefixToPath;
159 // private Multimap<Prefix, PushedFlowMod> pushedFlows;
160 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700161
Ray Milkey269ffb92014-04-03 14:43:30 -0700162 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700163
Ray Milkey269ffb92014-04-03 14:43:30 -0700164 // TODO: Fix for the new Topology Network Graph
165 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700166
Jonathan Hart284e70f2014-07-05 12:32:51 -0700167 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700168 private class TopologyChangeDetector implements Runnable {
169 @Override
170 public void run() {
171 log.debug("Running topology change detection task");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700172 // TODO: Fix the code below after topoLinkService was removed
Ray Milkey269ffb92014-04-03 14:43:30 -0700173 synchronized (linkUpdates) {
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700174
Ray Milkey269ffb92014-04-03 14:43:30 -0700175 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700176
Ray Milkey269ffb92014-04-03 14:43:30 -0700177 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700178
Ray Milkey269ffb92014-04-03 14:43:30 -0700179 Iterator<LDUpdate> it = linkUpdates.iterator();
180 while (it.hasNext()){
181 LDUpdate ldu = it.next();
182 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
183 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700184
Ray Milkey269ffb92014-04-03 14:43:30 -0700185 if (activeLinks.contains(l)){
186 it.remove();
187 }
188 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700189 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700190
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 if (!topologyReady) {
192 if (linkUpdates.isEmpty()) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700193 // All updates have been seen in network map.
194 // We can check if topology is ready
Ray Milkey269ffb92014-04-03 14:43:30 -0700195 log.debug("No known changes outstanding. Checking topology now");
196 checkStatus();
197 } else {
Jonathan Hart938a0152014-04-07 18:27:31 -0700198 // We know of some link updates that haven't propagated to the database yet
Ray Milkey269ffb92014-04-03 14:43:30 -0700199 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
200 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
201 }
202 }
203 }
204 }
Jonathan Hart284e70f2014-07-05 12:32:51 -0700205 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700206
Ray Milkey269ffb92014-04-03 14:43:30 -0700207 private void readConfiguration(String configFilename) {
208 File gatewaysFile = new File(configFilename);
209 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700210
Ray Milkey269ffb92014-04-03 14:43:30 -0700211 try {
212 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700213
Ray Milkey269ffb92014-04-03 14:43:30 -0700214 switches = config.getSwitches();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700215 interfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700216 for (Interface intf : config.getInterfaces()) {
217 interfaces.put(intf.getName(), intf);
218 }
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700219 bgpPeers = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700220 for (BgpPeer peer : config.getPeers()) {
221 bgpPeers.put(peer.getIpAddress(), peer);
222 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700223
Ray Milkey269ffb92014-04-03 14:43:30 -0700224 bgpdAttachmentPoint = new SwitchPort(
225 new Dpid(config.getBgpdAttachmentDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700226 new PortNumber(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700227
Ray Milkey269ffb92014-04-03 14:43:30 -0700228 bgpdMacAddress = config.getBgpdMacAddress();
229 vlan = config.getVlan();
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -0700230 } catch (JsonParseException | JsonMappingException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700231 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700232 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700233 } catch (IOException e) {
234 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700235 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700236 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700237
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700238 // Populate the interface Patricia Tree
Ray Milkey269ffb92014-04-03 14:43:30 -0700239 for (Interface intf : interfaces.values()) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700240 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
241 intf.getPrefixLength());
242 interfaceRoutes.put(prefix.toBinaryString(), intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700243 }
244 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700245
Ray Milkey269ffb92014-04-03 14:43:30 -0700246 @Override
247 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
248 Collection<Class<? extends IFloodlightService>> l
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700249 = new ArrayList<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700250 l.add(ISdnIpService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700251 l.add(IConfigInfoService.class);
252 return l;
253 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700254
Ray Milkey269ffb92014-04-03 14:43:30 -0700255 @Override
256 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
257 Map<Class<? extends IFloodlightService>, IFloodlightService> m
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700258 = new HashMap<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700259 m.put(ISdnIpService.class, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700260 m.put(IConfigInfoService.class, this);
261 return m;
262 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800263
Ray Milkey269ffb92014-04-03 14:43:30 -0700264 @Override
265 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
266 Collection<Class<? extends IFloodlightService>> l
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700267 = new ArrayList<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700268 l.add(IFloodlightProviderService.class);
269 l.add(IRestApiService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700270 l.add(IControllerRegistryService.class);
271 l.add(IPathCalcRuntimeService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700272 return l;
273 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700274
Ray Milkey269ffb92014-04-03 14:43:30 -0700275 @Override
276 public void init(FloodlightModuleContext context)
277 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700278
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700279 bgpRoutes = new ConcurrentInvertedRadixTree<>(
280 new DefaultByteArrayNodeFactory());
281 interfaceRoutes = new ConcurrentInvertedRadixTree<>(
282 new DefaultByteArrayNodeFactory());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700283
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700284 ribUpdates = new LinkedBlockingQueue<>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700285
Ray Milkey269ffb92014-04-03 14:43:30 -0700286 // Register floodlight provider and REST handler.
287 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
288 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
289 restApi = context.getServiceImpl(IRestApiService.class);
290 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800291
Komal Shah399a2922014-05-28 01:57:40 -0700292 controllerRegistryService = context.getServiceImpl(IControllerRegistryService.class);
293 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700294
295 //ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
296 //topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700297
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700298 pathsWaitingOnArp = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700299 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
300 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700301
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700302 pushedPaths = new HashMap<>();
303 prefixToPath = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700304// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700305 pushedFlowIds = HashMultimap.create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700306
Ray Milkey269ffb92014-04-03 14:43:30 -0700307 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700308
Ray Milkey269ffb92014-04-03 14:43:30 -0700309 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
310 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700311
Jonathan Hart938a0152014-04-07 18:27:31 -0700312 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700313 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
314 if (bgpdRestIp == null) {
315 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700316 throw new ConfigurationRuntimeException(
317 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700318 } else {
319 log.info("BgpdRestIp set to {}", bgpdRestIp);
320 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700321
Ray Milkey269ffb92014-04-03 14:43:30 -0700322 routerId = context.getConfigParams(this).get("RouterId");
323 if (routerId == null) {
324 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700325 throw new ConfigurationRuntimeException(
326 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700327 } else {
328 log.info("RouterId set to {}", routerId);
329 }
pingping-linba5c52f2014-02-11 16:52:01 -0800330
Ray Milkey269ffb92014-04-03 14:43:30 -0700331 String configFilenameParameter = context.getConfigParams(this).get("configfile");
332 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700333 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700334 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700335 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700336
Ray Milkey5df613b2014-04-15 10:50:56 -0700337 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700338 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700339
Ray Milkey269ffb92014-04-03 14:43:30 -0700340 @Override
341 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700342 restApi.addRestletRoutable(new SdnIpWebRoutable());
Komal Shah399a2922014-05-28 01:57:40 -0700343 restApi.addRestletRoutable(new SdnIpWebRoutableNew());
Ray Milkey269ffb92014-04-03 14:43:30 -0700344 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800345
Jonathan Hart938a0152014-04-07 18:27:31 -0700346 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700347 retrieveRib();
348 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800349
Ray Milkey269ffb92014-04-03 14:43:30 -0700350 @Override
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700351 public RadixTree<RibEntry> getPtree() {
352 return bgpRoutes;
Ray Milkey269ffb92014-04-03 14:43:30 -0700353 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700354
Ray Milkey269ffb92014-04-03 14:43:30 -0700355 @Override
356 public void clearPtree() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700357 log.warn("Clear table operation not supported");
Ray Milkey269ffb92014-04-03 14:43:30 -0700358 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700359
Ray Milkey269ffb92014-04-03 14:43:30 -0700360 @Override
Jonathan Hart31e15f12014-04-10 10:33:00 -0700361 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700362 return bgpdRestIp;
363 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700364
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 @Override
366 public String getRouterId() {
367 return routerId;
368 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700369
Ray Milkey269ffb92014-04-03 14:43:30 -0700370 private void retrieveRib() {
371 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
372 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700373
Jonathan Hart938a0152014-04-07 18:27:31 -0700374 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700375 return;
376 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700377
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700378 try {
379 response = response.replaceAll("\"", "'");
380 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
381 JSONArray ribArray = jsonObj.getJSONArray("rib");
382 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700383
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700384 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700385
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700386 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700387
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700388 for (int j = 0; j < size; j++) {
389 JSONObject ribEntry = ribArray.getJSONObject(j);
390 String prefix = ribEntry.getString("prefix");
391 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700392
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700393 // Insert each rib entry into the local rib
394 String[] substring = prefix.split("/");
395 String prefix1 = substring[0];
396 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700397
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700398 Prefix p;
399 try {
400 p = new Prefix(prefix1, Integer.parseInt(mask1));
401 } catch (NumberFormatException e) {
402 log.warn("Wrong mask format in RIB JSON: {}", mask1);
403 continue;
404 } catch (IllegalArgumentException e1) {
405 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
406 continue;
407 }
408
409 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
410
411 try {
412 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
413 } catch (InterruptedException e) {
414 log.debug("Interrupted while pushing onto update queue");
415 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700416 }
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700417 } catch (JSONException e) {
418 // TODO don't parse JSON manually
419 log.error("Error parsing inital route table JSON:", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700420 }
421 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700422
Ray Milkey269ffb92014-04-03 14:43:30 -0700423 @Override
424 public void newRibUpdate(RibUpdate update) {
425 try {
426 ribUpdates.put(update);
427 } catch (InterruptedException e) {
428 log.debug("Interrupted while putting on ribUpdates queue", e);
429 Thread.currentThread().interrupt();
430 }
431 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700432
Sho SHIMIZUba372192014-07-10 08:59:57 -0700433 private void processRibAdd(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700434 synchronized (this) {
435 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700436
Jonathan Hart938a0152014-04-07 18:27:31 -0700437 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700438
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700439 RibEntry rib = bgpRoutes.put(prefix.toBinaryString(), update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700440
Jonathan Hart938a0152014-04-07 18:27:31 -0700441 if (rib != null && !rib.equals(update.getRibEntry())) {
442 // There was an existing nexthop for this prefix. This update supersedes that,
443 // so we need to remove the old flows for this prefix from the switches
Ray Milkey7531a342014-04-11 15:08:12 -0700444 executeDeletePrefix(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700445 }
Ray Milkey5d406012014-04-08 14:44:41 -0700446
Jonathan Hart938a0152014-04-07 18:27:31 -0700447 if (update.getRibEntry().getNextHop().equals(
448 InetAddresses.forString("0.0.0.0"))) {
449 // Route originated by SDN domain
450 // We don't handle these at the moment
451 log.debug("Own route {} to {}", prefix,
452 update.getRibEntry().getNextHop().getHostAddress());
453 return;
454 }
Ray Milkey5d406012014-04-08 14:44:41 -0700455
Ray Milkey7531a342014-04-11 15:08:12 -0700456 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700457 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700458 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700459
Ray Milkey7531a342014-04-11 15:08:12 -0700460 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700461 // TODO: Fix the code below. Note that "deviceStorage" was removed.
462
463 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700464 Prefix prefix = update.getPrefix();
465 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700466
Ray Milkey269ffb92014-04-03 14:43:30 -0700467 InetAddress dstIpAddress = rib.getNextHop();
468 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800469
Ray Milkey269ffb92014-04-03 14:43:30 -0700470 // See if we know the MAC address of the next hop
471 // 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 -0700472 IDeviceObject nextHopDevice =
473 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700474
Ray Milkey269ffb92014-04-03 14:43:30 -0700475 if (nextHopDevice == null){
476 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
477 prefixesWaitingOnArp.put(dstIpAddress,
478 new RibUpdate(Operation.UPDATE, prefix, rib));
479 proxyArp.sendArpRequest(dstIpAddress, this, true);
480 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800481
Ray Milkey269ffb92014-04-03 14:43:30 -0700482 }
483 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700484
Ray Milkey269ffb92014-04-03 14:43:30 -0700485 // Find the attachment point (egress interface) of the next hop
486 Interface egressInterface = null;
487 if (bgpPeers.containsKey(dstIpAddress)) {
488 //Route to a peer
489 log.debug("Route to peer {}", dstIpAddress);
490 BgpPeer peer = bgpPeers.get(dstIpAddress);
491 egressInterface = interfaces.get(peer.getInterfaceName());
492 } else {
493 //Route to non-peer
494 log.debug("Route to non-peer {}", dstIpAddress);
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700495 egressInterface = interfacePtree.match(
Ray Milkey269ffb92014-04-03 14:43:30 -0700496 new Prefix(dstIpAddress.getAddress(), 32));
497 if (egressInterface == null) {
498 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
499 return;
500 }
501 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700502
Ray Milkey269ffb92014-04-03 14:43:30 -0700503 if (nextHopMacAddress == null) {
504 prefixesWaitingOnArp.put(dstIpAddress,
505 new RibUpdate(Operation.UPDATE, prefix, rib));
506 proxyArp.sendArpRequest(dstIpAddress, this, true);
507 return;
508 } else {
509 if (!bgpPeers.containsKey(dstIpAddress)) {
510 //If the prefix is for a non-peer we need to ensure there's a path,
511 //and push one if there isn't.
512 Path path = pushedPaths.get(dstIpAddress);
513 if (path == null) {
514 path = new Path(egressInterface, dstIpAddress);
515 calculateAndPushPath(path, nextHopMacAddress);
516 pushedPaths.put(dstIpAddress, path);
517 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700518
Ray Milkey269ffb92014-04-03 14:43:30 -0700519 path.incrementUsers();
520 prefixToPath.put(prefix, path);
521 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700522
Ray Milkey269ffb92014-04-03 14:43:30 -0700523 //For all prefixes we need to add the first-hop mac-rewriting flows
524 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
525 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700526 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700527 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700528
Ray Milkey269ffb92014-04-03 14:43:30 -0700529 /**
530 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
Ray Milkeyb41100a2014-04-10 10:42:15 -0700531 * to all other border switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700532 */
533 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
534 MACAddress nextHopMacAddress) {
535 log.debug("Adding flows for prefix {}, next hop mac {}",
536 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700537
Ray Milkey269ffb92014-04-03 14:43:30 -0700538 FlowPath flowPath = new FlowPath();
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700539 flowPath.setInstallerId(callerId);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700540
Ray Milkey269ffb92014-04-03 14:43:30 -0700541 // Set flowPath FlowPathType and FlowPathUserState
542 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
543 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800544
Ray Milkey269ffb92014-04-03 14:43:30 -0700545 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
546 // only to the first-host switches
547 FlowPathFlags flowPathFlags = new FlowPathFlags();
548 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
549 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800550
Ray Milkey269ffb92014-04-03 14:43:30 -0700551 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700552 SwitchPort dstPort =
553 new SwitchPort(new Dpid(egressInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700554 new PortNumber(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800555
Ray Milkey269ffb92014-04-03 14:43:30 -0700556 // We only need one flow mod per switch, so pick one interface on each switch
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700557 Map<Long, Interface> srcInterfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700558 for (Interface intf : interfaces.values()) {
559 if (!srcInterfaces.containsKey(intf.getDpid())
560 && !intf.equals(egressInterface)) {
561 srcInterfaces.put(intf.getDpid(), intf);
562 }
563 }
564 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800565
Ray Milkey269ffb92014-04-03 14:43:30 -0700566 if (egressInterface.equals(srcInterface)) {
567 continue;
568 }
pingping-linba5c52f2014-02-11 16:52:01 -0800569
Ray Milkey269ffb92014-04-03 14:43:30 -0700570 // Create flowPath FlowId
571 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800572
Ray Milkey269ffb92014-04-03 14:43:30 -0700573 // Create DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700574 SwitchPort srcPort =
575 new SwitchPort(new Dpid(srcInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700576 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800577
Ray Milkey269ffb92014-04-03 14:43:30 -0700578 DataPath dataPath = new DataPath();
579 dataPath.setSrcPort(srcPort);
580 dataPath.setDstPort(dstPort);
581 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800582
Ray Milkey269ffb92014-04-03 14:43:30 -0700583 // Create flow path matching condition(s): IPv4 Prefix
584 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700585 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700586 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
587 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
588 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300589
Ray Milkey269ffb92014-04-03 14:43:30 -0700590 /*
591 * Create the Flow Entry Action(s): dst-MAC rewrite action
592 */
593 FlowEntryActions flowEntryActions = new FlowEntryActions();
594 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
595 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
596 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
597 flowEntryActions.addAction(flowEntryAction1);
598 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800599
Ray Milkey269ffb92014-04-03 14:43:30 -0700600 // Flow Path installation, only to first hop switches
601 // TODO: Add the flow by using the new Path Intent framework
602 /*
603 if (flowManagerService.addFlow(flowPath) == null) {
604 log.error("Failed to install flow path to the first hop for " +
605 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
606 nextHopMacAddress);
607 }
608 else {
609 log.debug("Successfully installed flow path to the first hop " +
610 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
611 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800612
Ray Milkey269ffb92014-04-03 14:43:30 -0700613 pushedFlowIds.put(prefix, flowPath.flowId());
614 }
615 */
616 }
617 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700618
Sho SHIMIZUba372192014-07-10 08:59:57 -0700619 private void processRibDelete(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700620 synchronized (this) {
621 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700622
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700623 //if (ptree.remove(prefix, update.getRibEntry())) {
624 // TODO check the change of logic here - remove doesn't check that the
625 // rib entry was what we expected (and we can't do this concurrently)
626 if (bgpRoutes.remove(prefix.toBinaryString())) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700627 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700628 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700629 * If no entry was removed, the <prefix, nexthop> wasn't there so
630 * it's probably already been removed and we don't need to do anything
631 */
Ray Milkey7531a342014-04-11 15:08:12 -0700632 executeDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart938a0152014-04-07 18:27:31 -0700633 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700634 }
635 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700636
Ray Milkey7531a342014-04-11 15:08:12 -0700637 private void executeDeletePrefix(Prefix prefix, RibEntry ribEntry) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700638 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700639
Ray Milkey269ffb92014-04-03 14:43:30 -0700640 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700641
Ray Milkey269ffb92014-04-03 14:43:30 -0700642 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
643 log.debug("Getting path for route with non-peer nexthop");
644 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700645
Ray Milkey269ffb92014-04-03 14:43:30 -0700646 if (path != null) {
647 //path could be null if we added to the Ptree but didn't push
648 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700649
Ray Milkey269ffb92014-04-03 14:43:30 -0700650 path.decrementUsers();
651 if (path.getUsers() <= 0 && !path.isPermanent()) {
652 deletePath(path);
653 pushedPaths.remove(path.getDstIpAddress());
654 }
655 }
656 }
657 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700658
Ray Milkey269ffb92014-04-03 14:43:30 -0700659 // TODO have not tested this module
660 private void deletePrefixFlows(Prefix prefix) {
661 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700662
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700663 //
664 // TODO: Delete the flow by using the new Path Intent framework
665 // NOTE: During the refactoring of the code below, if obtaining
666 // the values of the removed flowIds is needed, the first
667 // removeAll() statement should be replaced with the second removeAll()
668 // statement.
669 //
670 pushedFlowIds.removeAll(prefix);
671 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700672 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
673 for (FlowId flowId : flowIds) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700674 if (log.isTraceEnabled()) {
675 //Trace the flow status by flowPath in the switch before deleting it
676 log.trace("Pushing a DELETE flow mod to flowPath : {}",
677 flowManagerService.getFlow(flowId).toString());
678 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700679
Ray Milkey269ffb92014-04-03 14:43:30 -0700680 if( flowManagerService.deleteFlow(flowId))
681 {
682 log.debug("Successfully deleted FlowId: {}",flowId);
683 }
684 else
685 {
686 log.debug("Failed to delete FlowId: {}",flowId);
687 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700688 }
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700689 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700690 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700691
Ray Milkey269ffb92014-04-03 14:43:30 -0700692 // TODO need to record the path and then delete here
693 private void deletePath(Path path) {
694 log.debug("Deleting flows for path to {}",
695 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700696
Ray Milkey269ffb92014-04-03 14:43:30 -0700697 // TODO need update
698 /*for (PushedFlowMod pfm : path.getFlowMods()) {
699 if (log.isTraceEnabled()) {
700 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
701 new Object[] {HexString.toHexString(pfm.getDpid()),
702 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
703 });
704 }
pingping-linba5c52f2014-02-11 16:52:01 -0800705
Ray Milkey269ffb92014-04-03 14:43:30 -0700706 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
707 }*/
708 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700709
710
Ray Milkey269ffb92014-04-03 14:43:30 -0700711 //TODO test next-hop changes
712 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800713
Ray Milkey269ffb92014-04-03 14:43:30 -0700714 /**
715 * On startup, we need to calculate a full mesh of paths between all gateway
Ray Milkeyb41100a2014-04-10 10:42:15 -0700716 * switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700717 */
718 private void setupFullMesh() {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700719 // TODO: Fix the code below. Note that "deviceStorage" was removed.
720
721 /*
722
Ray Milkey269ffb92014-04-03 14:43:30 -0700723 //For each border router, calculate and install a path from every other
724 //border switch to said border router. However, don't install the entry
725 //in to the first hop switch, as we need to install an entry to rewrite
726 //for each prefix received. This will be done later when prefixes have
727 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700728
Ray Milkey269ffb92014-04-03 14:43:30 -0700729 for (BgpPeer peer : bgpPeers.values()) {
730 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700731
Ray Milkey269ffb92014-04-03 14:43:30 -0700732 //We know there's not already a Path here pushed, because this is
733 //called before all other routing
734 Path path = new Path(peerInterface, peer.getIpAddress());
735 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700736
Ray Milkey269ffb92014-04-03 14:43:30 -0700737 //See if we know the MAC address of the peer. If not we can't
738 //do anything until we learn it
Ray Milkey269ffb92014-04-03 14:43:30 -0700739 MACAddress macAddress = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700740 IDeviceObject nextHopDevice =
741 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800742
Ray Milkey269ffb92014-04-03 14:43:30 -0700743 if(nextHopDevice == null){
744 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
745 //Put in the pending paths list first
746 pathsWaitingOnArp.put(peer.getIpAddress(), path);
747 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
748 continue;
749 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700750
Ray Milkey269ffb92014-04-03 14:43:30 -0700751 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
pingping-linba5c52f2014-02-11 16:52:01 -0800752
Ray Milkey269ffb92014-04-03 14:43:30 -0700753 if (macAddress == null) {
754 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
755 //Put in the pending paths list first
756 pathsWaitingOnArp.put(peer.getIpAddress(), path);
757 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
758 continue;
759 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700760
Ray Milkey269ffb92014-04-03 14:43:30 -0700761 //If we know the MAC, lets go ahead and push the paths to this peer
762 calculateAndPushPath(path, macAddress);
763 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700764 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700765 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700766
Ray Milkey269ffb92014-04-03 14:43:30 -0700767 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
768 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700769
Ray Milkey269ffb92014-04-03 14:43:30 -0700770 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
771 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800772
Ray Milkey269ffb92014-04-03 14:43:30 -0700773 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800774
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700775 flowPath.setInstallerId(callerId);
pingping-linba5c52f2014-02-11 16:52:01 -0800776
Ray Milkey269ffb92014-04-03 14:43:30 -0700777 // Set flowPath FlowPathType and FlowPathUserState
778 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
779 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800780
Ray Milkey269ffb92014-04-03 14:43:30 -0700781 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
782 FlowPathFlags flowPathFlags = new FlowPathFlags();
783 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
784 flowPath.setFlowPathFlags(flowPathFlags);
785
786 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700787 SwitchPort dstPort =
788 new SwitchPort(new Dpid(dstInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700789 new PortNumber(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800790
Ray Milkey269ffb92014-04-03 14:43:30 -0700791 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800792
Ray Milkey269ffb92014-04-03 14:43:30 -0700793 if (dstInterface.equals(srcInterface)) {
794 continue;
795 }
pingping-linba5c52f2014-02-11 16:52:01 -0800796
Ray Milkey269ffb92014-04-03 14:43:30 -0700797 // Create flowPath FlowId
798 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800799
Ray Milkey269ffb92014-04-03 14:43:30 -0700800 // Create the DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700801 SwitchPort srcPort =
802 new SwitchPort(new Dpid(srcInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700803 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800804
Ray Milkey269ffb92014-04-03 14:43:30 -0700805 DataPath dataPath = new DataPath();
806 dataPath.setSrcPort(srcPort);
807 dataPath.setDstPort(dstPort);
808 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800809
Ray Milkey269ffb92014-04-03 14:43:30 -0700810 // Create the Flow Path Match condition(s)
811 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700812 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700813 flowEntryMatch.enableDstMac(dstMacAddress);
814 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800815
Ray Milkey269ffb92014-04-03 14:43:30 -0700816 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
817 // Shortest Path Flow, and is always the last action for the Flow Entries
818 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
819 // TODO: Add the flow by using the new Path Intent framework
820 /*
821 if (flowManagerService.addFlow(flowPath) == null) {
822 log.error("Failed to set up MAC based forwarding path to {}, {}",
823 path.getDstIpAddress().getHostAddress(),dstMacAddress);
824 }
825 else {
826 log.debug("Successfully set up MAC based forwarding path to {}, {}",
827 path.getDstIpAddress().getHostAddress(),dstMacAddress);
828 }
829 */
830 }
831 }
pingping-linba5c52f2014-02-11 16:52:01 -0800832
Komal Shah399a2922014-05-28 01:57:40 -0700833 @Override
834 public void beginRoutingNew() {
835 setupBgpPathsNew();
836
837 //setupFullMesh();
838
839 //Suppress link discovery on external-facing router ports
840
841 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -0700842 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Komal Shah399a2922014-05-28 01:57:40 -0700843 }
844
845 bgpUpdatesExecutor.execute(new Runnable() {
846 @Override
847 public void run() {
848 doUpdatesThread();
849 }
850 });
851 }
852
Ray Milkey269ffb92014-04-03 14:43:30 -0700853 /**
Komal Shah399a2922014-05-28 01:57:40 -0700854 * Setup the Paths to the BGP Daemon.
855 *
856 * Run a loop for all of the bgpPeers
857 * Push flow from BGPd to the peer
858 * Push flow from peer to BGPd
859 * Parameters to pass to the intent are as follows:
860 * String id,
861 * long srcSwitch, long srcPort, long srcMac, int srcIP,
862 * long dstSwitch, long dstPort, long dstMac, int dstIP
863 */
864 private void setupBgpPathsNew() {
865 IntentOperationList operations = new IntentOperationList();
866 for (BgpPeer bgpPeer : bgpPeers.values()) {
867 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
868 //Inet4Address.
869 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
870 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700871 String fwdIntentId = caller + ":" + controllerRegistryService.getNextUniqueId();
872 String bwdIntentId = caller + ":" + controllerRegistryService.getNextUniqueId();
Komal Shah399a2922014-05-28 01:57:40 -0700873 SwitchPort srcPort =
874 new SwitchPort(bgpdAttachmentPoint.dpid(),
875 bgpdAttachmentPoint.port());
876 SwitchPort dstPort =
877 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700878 new PortNumber(peerInterface.getSwitchPort().port()));
Komal Shah399a2922014-05-28 01:57:40 -0700879 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
880 srcPort.dpid().value(), srcPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, srcIP,
881 dstPort.dpid().value(), dstPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, dstIP);
882 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700883 dstPort.dpid().value(), dstPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, dstIP,
884 srcPort.dpid().value(), srcPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700885 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
886 operations.add(operator, fwdIntent);
887 operations.add(operator, bwdIntent);
888 }
889 pathRuntime.executeIntentOperations(operations);
890 }
891
892 /*
Jonathan Hart938a0152014-04-07 18:27:31 -0700893 * Proactively install all BGP traffic paths from BGP host attachment point
Ray Milkeyb41100a2014-04-10 10:42:15 -0700894 * in SDN network to all the virtual gateways to BGP peers in other networks.
Ray Milkey269ffb92014-04-03 14:43:30 -0700895 */
896 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200897
Ray Milkey269ffb92014-04-03 14:43:30 -0700898 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800899
Ray Milkey269ffb92014-04-03 14:43:30 -0700900 FlowPath flowPath = new FlowPath();
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700901 flowPath.setInstallerId(callerId);
pingping-linba5c52f2014-02-11 16:52:01 -0800902
Ray Milkey269ffb92014-04-03 14:43:30 -0700903 // Set flowPath FlowPathType and FlowPathUserState
904 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
905 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800906
Ray Milkey269ffb92014-04-03 14:43:30 -0700907 // Install flow paths between BGPd and its peers
908 // There is no need to set the FlowPathFlags
909 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800910
Ray Milkey269ffb92014-04-03 14:43:30 -0700911 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Ray Milkey269ffb92014-04-03 14:43:30 -0700912 // Create the Flow Path Match condition(s)
913 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700914 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
pingping-linba5c52f2014-02-11 16:52:01 -0800915
Ray Milkey269ffb92014-04-03 14:43:30 -0700916 // Match both source address and dest address
917 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress() + "/32");
Komal Shah399a2922014-05-28 01:57:40 -0700918
Ray Milkey269ffb92014-04-03 14:43:30 -0700919 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800920
Ray Milkey269ffb92014-04-03 14:43:30 -0700921 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress().getHostAddress() + "/32");
922 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800923
Ray Milkey269ffb92014-04-03 14:43:30 -0700924 // Match TCP protocol
925 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800926
Ray Milkey269ffb92014-04-03 14:43:30 -0700927 // Match destination TCP port
928 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
929 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800930
Ray Milkey269ffb92014-04-03 14:43:30 -0700931 /**
932 * Create the DataPath: BGP -> BGP peer
933 */
934 // Flow path for src-TCP-port
935 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800936
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700937 SwitchPort srcPort =
938 new SwitchPort(bgpdAttachmentPoint.dpid(),
939 bgpdAttachmentPoint.port());
Ray Milkey269ffb92014-04-03 14:43:30 -0700940 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800941
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700942 SwitchPort dstPort =
943 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700944 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700945 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800946
Ray Milkey269ffb92014-04-03 14:43:30 -0700947 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800948
Ray Milkey269ffb92014-04-03 14:43:30 -0700949 // TODO: Add the flow by using the new Path Intent framework
950 /*
951 if (flowManagerService.addFlow(flowPath) == null) {
952 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
953 bgpPeer.getIpAddress().getHostAddress());
954 }
955 else {
956 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
957 bgpPeer.getIpAddress().getHostAddress());
958 }
959 */
pingping-linba5c52f2014-02-11 16:52:01 -0800960
Ray Milkey269ffb92014-04-03 14:43:30 -0700961 // Disable dst-TCP-port, and set src-TCP-port
962 flowEntryMatch.disableDstTcpUdpPort();
963 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
964 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800965
Ray Milkey269ffb92014-04-03 14:43:30 -0700966 // Create a new FlowId
967 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800968
Ray Milkey269ffb92014-04-03 14:43:30 -0700969 // TODO: Add the flow by using the new Path Intent framework
970 /*
971 if (flowManagerService.addFlow(flowPath) == null) {
972 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
973 bgpPeer.getIpAddress().getHostAddress());
974 }
975 else {
976 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
977 bgpPeer.getIpAddress().getHostAddress());
978 }
979 */
pingping-linba5c52f2014-02-11 16:52:01 -0800980
Ray Milkey269ffb92014-04-03 14:43:30 -0700981 /**
982 * Create the DataPath: BGP <-BGP peer
983 */
984 // Reversed BGP flow path for src-TCP-port
985 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800986
Ray Milkey2476cac2014-04-08 11:03:21 -0700987 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800988
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700989 SwitchPort reverseDstPort =
Komal Shah399a2922014-05-28 01:57:40 -0700990 new SwitchPort(bgpdAttachmentPoint.dpid(),
991 bgpdAttachmentPoint.port());
Ray Milkey2476cac2014-04-08 11:03:21 -0700992 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800993
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700994 SwitchPort reverseSrcPort =
Komal Shah399a2922014-05-28 01:57:40 -0700995 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700996 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey2476cac2014-04-08 11:03:21 -0700997 reverseDataPath.setSrcPort(reverseSrcPort);
998 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800999
Jonathan Hart938a0152014-04-07 18:27:31 -07001000 // Reverse the dst IP and src IP addresses
Ray Milkey269ffb92014-04-03 14:43:30 -07001001 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
1002 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
1003 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001004
Ray Milkey269ffb92014-04-03 14:43:30 -07001005 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001006
Ray Milkey269ffb92014-04-03 14:43:30 -07001007 // TODO: Add the flow by using the new Path Intent framework
1008 /*
1009 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001010
Ray Milkey269ffb92014-04-03 14:43:30 -07001011 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
1012 bgpPeer.getIpAddress().getHostAddress());
1013 }
1014 else {
1015 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
1016 bgpPeer.getIpAddress().getHostAddress());
1017 }
1018 */
pingping-linba5c52f2014-02-11 16:52:01 -08001019
Ray Milkey269ffb92014-04-03 14:43:30 -07001020 // Reversed BGP flow path for dst-TCP-port
1021 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001022
Ray Milkey269ffb92014-04-03 14:43:30 -07001023 // Disable src-TCP-port, and set the dst-TCP-port
1024 flowEntryMatch.disableSrcTcpUdpPort();
1025 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
1026 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001027
Ray Milkey269ffb92014-04-03 14:43:30 -07001028 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001029
Ray Milkey269ffb92014-04-03 14:43:30 -07001030 // TODO: Add the flow by using the new Path Intent framework
1031 /*
1032 if (flowManagerService.addFlow(flowPath) == null) {
1033 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1034 bgpPeer.getIpAddress().getHostAddress());
1035 }
1036 else {
1037 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1038 bgpPeer.getIpAddress().getHostAddress());
1039 }
1040 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001041
Ray Milkey269ffb92014-04-03 14:43:30 -07001042 /**
1043 * ICMP paths between BGPd and its peers
1044 */
Jonathan Hart938a0152014-04-07 18:27:31 -07001045 // match ICMP protocol BGP <- Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001046 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001047
Ray Milkey269ffb92014-04-03 14:43:30 -07001048 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
1049 flowEntryMatch.disableSrcTcpUdpPort();
1050 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -08001051
Ray Milkey269ffb92014-04-03 14:43:30 -07001052 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001053
Ray Milkey2476cac2014-04-08 11:03:21 -07001054 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001055
Ray Milkey269ffb92014-04-03 14:43:30 -07001056 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001057
Ray Milkey269ffb92014-04-03 14:43:30 -07001058 // TODO: Add the flow by using the new Path Intent framework
1059 /*
1060 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001061
Ray Milkey269ffb92014-04-03 14:43:30 -07001062 log.error("Failed to set up ICMP path BGP <- Peer {}",
1063 bgpPeer.getIpAddress().getHostAddress());
1064 }
1065 else {
1066 log.debug("Successfully set up ICMP path BGP <- Peer {}",
1067 bgpPeer.getIpAddress().getHostAddress());
1068 }
1069 */
pingping-linba5c52f2014-02-11 16:52:01 -08001070
Jonathan Hart938a0152014-04-07 18:27:31 -07001071 // match ICMP protocol BGP -> Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001072 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001073
Ray Milkey269ffb92014-04-03 14:43:30 -07001074 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
1075 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
1076 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001077
Ray Milkey269ffb92014-04-03 14:43:30 -07001078 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001079
Ray Milkey269ffb92014-04-03 14:43:30 -07001080 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001081
Ray Milkey269ffb92014-04-03 14:43:30 -07001082 // TODO: Add the flow by using the new Path Intent framework
1083 /*
1084 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001085
Ray Milkey269ffb92014-04-03 14:43:30 -07001086 log.error("Failed to set up ICMP path BGP -> Peer {}",
1087 bgpPeer.getIpAddress().getHostAddress());
1088 }
1089 else {
1090 log.debug("Successfully set up ICMP path BGP -> Peer {}",
1091 bgpPeer.getIpAddress().getHostAddress());
1092 }
1093 */
1094 }
1095 }
pingping-linba5c52f2014-02-11 16:52:01 -08001096
Ray Milkey269ffb92014-04-03 14:43:30 -07001097 @Override
1098 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
1099 log.debug("Received ARP response: {} => {}",
1100 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001101
Ray Milkey269ffb92014-04-03 14:43:30 -07001102 /*
1103 * We synchronize on this to prevent changes to the ptree while we're pushing
1104 * flows to the switches. If the ptree changes, the ptree and switches
1105 * could get out of sync.
1106 */
1107 synchronized (this) {
1108 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001109
Ray Milkey269ffb92014-04-03 14:43:30 -07001110 if (path != null) {
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -07001111 log.debug("Pushing path to {} at {} on {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001112 path.getDstIpAddress().getHostAddress(), macAddress,
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -07001113 path.getDstInterface().getSwitchPort());
Jonathan Hart938a0152014-04-07 18:27:31 -07001114 // These paths should always be to BGP peers. Paths to non-peers are
1115 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -07001116 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001117 // A path already got pushed to this endpoint while we were waiting
1118 // for ARP. We'll copy over the permanent attribute if it is set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -07001119 if (path.isPermanent()) {
1120 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1121 }
1122 } else {
1123 calculateAndPushPath(path, macAddress);
1124 pushedPaths.put(path.getDstIpAddress(), path);
1125 }
1126 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001127
Ray Milkey269ffb92014-04-03 14:43:30 -07001128 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001129
Ray Milkey269ffb92014-04-03 14:43:30 -07001130 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001131 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001132
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001133 RibEntry rib = bgpRoutes.getValueForExactKey(
1134 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -07001135 if (rib != null && rib.equals(update.getRibEntry())) {
1136 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1137 rib.getNextHop().getHostAddress());
Jonathan Hart938a0152014-04-07 18:27:31 -07001138 // We only push prefix flows if the prefix is still in the ptree
1139 // and the next hop is the same as our update. The prefix could
1140 // have been removed while we were waiting for the ARP, or the
1141 // next hop could have changed.
Ray Milkey7531a342014-04-11 15:08:12 -07001142 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -07001143 } else {
1144 log.debug("Received ARP response, but {},{} is no longer in ptree",
1145 update.getPrefix(), update.getRibEntry());
1146 }
1147 }
1148 }
1149 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001150
Jonathan Hart938a0152014-04-07 18:27:31 -07001151 // TODO wait the priority module of the flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001152 private void setupArpFlows() {
1153 OFMatch match = new OFMatch();
1154 match.setDataLayerType(Ethernet.TYPE_ARP);
1155 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001156
Ray Milkey269ffb92014-04-03 14:43:30 -07001157 OFFlowMod fm = new OFFlowMod();
1158 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001159
Ray Milkey269ffb92014-04-03 14:43:30 -07001160 OFActionOutput action = new OFActionOutput();
1161 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1162 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001163 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -07001164 actions.add(action);
1165 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001166
Ray Milkey269ffb92014-04-03 14:43:30 -07001167 fm.setIdleTimeout((short) 0)
1168 .setHardTimeout((short) 0)
1169 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1170 .setCookie(0)
1171 .setCommand(OFFlowMod.OFPFC_ADD)
1172 .setPriority(ARP_PRIORITY)
1173 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001174
Ray Milkey269ffb92014-04-03 14:43:30 -07001175 for (String strdpid : switches) {
1176 flowCache.write(HexString.toLong(strdpid), fm);
1177 }
1178 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001179
Jonathan Hart938a0152014-04-07 18:27:31 -07001180 // TODO need update, waiting for the priority feature from flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001181 private void setupDefaultDropFlows() {
1182 OFFlowMod fm = new OFFlowMod();
1183 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -07001184 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001185
Ray Milkey269ffb92014-04-03 14:43:30 -07001186 fm.setIdleTimeout((short) 0)
1187 .setHardTimeout((short) 0)
1188 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1189 .setCookie(0)
1190 .setCommand(OFFlowMod.OFPFC_ADD)
1191 .setPriority((short) 0)
1192 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001193
Ray Milkey269ffb92014-04-03 14:43:30 -07001194 OFFlowMod fmLLDP;
1195 OFFlowMod fmBDDP;
1196 try {
1197 fmLLDP = fm.clone();
1198 fmBDDP = fm.clone();
1199 } catch (CloneNotSupportedException e1) {
1200 log.error("Error cloning flow mod", e1);
1201 return;
1202 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001203
Ray Milkey269ffb92014-04-03 14:43:30 -07001204 OFMatch matchLLDP = new OFMatch();
1205 matchLLDP.setDataLayerType((short) 0x88cc);
1206 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1207 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001208
Ray Milkey269ffb92014-04-03 14:43:30 -07001209 OFMatch matchBDDP = new OFMatch();
1210 matchBDDP.setDataLayerType((short) 0x8942);
1211 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1212 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001213
Ray Milkey269ffb92014-04-03 14:43:30 -07001214 OFActionOutput action = new OFActionOutput();
1215 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1216 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001217 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -07001218 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001219
Ray Milkey269ffb92014-04-03 14:43:30 -07001220 fmLLDP.setActions(actions);
1221 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001222
Ray Milkey269ffb92014-04-03 14:43:30 -07001223 fmLLDP.setPriority(ARP_PRIORITY);
1224 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1225 fmBDDP.setPriority(ARP_PRIORITY);
1226 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001227
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001228 List<OFFlowMod> flowModList = new ArrayList<>(3);
Ray Milkey269ffb92014-04-03 14:43:30 -07001229 flowModList.add(fm);
1230 flowModList.add(fmLLDP);
1231 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001232
Ray Milkey269ffb92014-04-03 14:43:30 -07001233 for (String strdpid : switches) {
1234 flowCache.write(HexString.toLong(strdpid), flowModList);
1235 }
1236 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001237
Ray Milkey269ffb92014-04-03 14:43:30 -07001238 private void beginRouting() {
1239 log.debug("Topology is now ready, beginning routing function");
1240 // TODO: Fix for the new Topology Network Graph
1241 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001242
Ray Milkey269ffb92014-04-03 14:43:30 -07001243 // Wait Pavlin's API. We need the following functions.
1244 /*setupArpFlows();
1245 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001246
Ray Milkey269ffb92014-04-03 14:43:30 -07001247 setupBgpPaths();
1248 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001249
Ray Milkey269ffb92014-04-03 14:43:30 -07001250 //Suppress link discovery on external-facing router ports
1251 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -07001252 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001253 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001254
Ray Milkey269ffb92014-04-03 14:43:30 -07001255 bgpUpdatesExecutor.execute(new Runnable() {
1256 @Override
1257 public void run() {
1258 doUpdatesThread();
1259 }
1260 });
1261 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001262
Jonathan Hart938a0152014-04-07 18:27:31 -07001263 // Before inserting the paths for BGP traffic, we should check whether
1264 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001265 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001266 // TODO: Fix the code below after topoSwitchSerice was removed
1267 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001268 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001269
Ray Milkey269ffb92014-04-03 14:43:30 -07001270 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1271 getActiveSwitches().iterator();
1272 while(activeSwitches.hasNext())
1273 {
1274 ISwitchObject switchObject = activeSwitches.next();
1275 if (switchObject.getDPID().equals(dpid)) {
1276 break;
1277 }
1278 if(activeSwitches.hasNext() == false) {
1279 log.debug("Not all switches are here yet");
1280 return;
1281 }
1282 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001283 }
1284 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001285 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001286 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001287
Jonathan Hart938a0152014-04-07 18:27:31 -07001288 // Actually we only need to go half way round to verify full mesh connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001289 private void checkTopologyReady() {
1290 for (Interface dstInterface : interfaces.values()) {
1291 for (Interface srcInterface : interfaces.values()) {
1292 if (dstInterface.equals(srcInterface)) {
1293 continue;
1294 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001295
Ray Milkey269ffb92014-04-03 14:43:30 -07001296 // TODO: Fix for the new Topology Network Graph
1297 /*
1298 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1299 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001300
Ray Milkey269ffb92014-04-03 14:43:30 -07001301 if (shortestPath == null){
1302 log.debug("Shortest path between {} and {} not found",
1303 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1304 return;
1305 }
1306 */
1307 }
1308 }
1309 topologyReady = true;
1310 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001311
Ray Milkey269ffb92014-04-03 14:43:30 -07001312 private void checkStatus() {
1313 if (!switchesConnected) {
1314 checkSwitchesConnected();
1315 }
1316 boolean oldTopologyReadyStatus = topologyReady;
1317 if (switchesConnected && !topologyReady) {
1318 checkTopologyReady();
1319 }
1320 if (!oldTopologyReadyStatus && topologyReady) {
1321 beginRouting();
1322 }
1323 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001324
Ray Milkey269ffb92014-04-03 14:43:30 -07001325 private void doUpdatesThread() {
1326 boolean interrupted = false;
1327 try {
1328 while (true) {
1329 try {
1330 RibUpdate update = ribUpdates.take();
1331 switch (update.getOperation()) {
1332 case UPDATE:
1333 if (validateUpdate(update)) {
1334 processRibAdd(update);
1335 } else {
1336 log.debug("Rib UPDATE out of order: {} via {}",
1337 update.getPrefix(), update.getRibEntry().getNextHop());
1338 }
1339 break;
1340 case DELETE:
1341 if (validateUpdate(update)) {
1342 processRibDelete(update);
1343 } else {
1344 log.debug("Rib DELETE out of order: {} via {}",
1345 update.getPrefix(), update.getRibEntry().getNextHop());
1346 }
1347 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -07001348 default:
1349 log.error("Unknown operation {}", update.getOperation());
1350 break;
Ray Milkey269ffb92014-04-03 14:43:30 -07001351 }
1352 } catch (InterruptedException e) {
1353 log.debug("Interrupted while taking from updates queue", e);
1354 interrupted = true;
1355 } catch (Exception e) {
1356 log.debug("exception", e);
1357 }
1358 }
1359 } finally {
1360 if (interrupted) {
1361 Thread.currentThread().interrupt();
1362 }
1363 }
1364 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001365
Ray Milkey269ffb92014-04-03 14:43:30 -07001366 private boolean validateUpdate(RibUpdate update) {
1367 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001368 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
1369 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001370
Ray Milkey269ffb92014-04-03 14:43:30 -07001371 //If there is no existing entry we must assume this is the most recent
1372 //update. However this might not always be the case as we might have a
1373 //POST then DELETE reordering.
1374 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1375 if (oldEntry == null) {
1376 return true;
1377 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001378
Ray Milkey269ffb92014-04-03 14:43:30 -07001379 // This handles the case where routes are gathered in the initial
1380 // request because they don't have sequence number info
1381 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1382 return true;
1383 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001384
Ray Milkey269ffb92014-04-03 14:43:30 -07001385 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1386 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001387 }
Ray Milkey4985f212014-04-10 16:57:05 -07001388
1389 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
1390 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -07001391 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001392
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001393 private Interface longestInterfacePrefixMatch(InetAddress address) {
1394 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
1395 Prefix.MAX_PREFIX_LENGTH);
1396 Iterator<Interface> it =
1397 interfaceRoutes.getValuesForKeysPrefixing(
1398 prefixToSearchFor.toBinaryString()).iterator();
1399 Interface intf = null;
1400 // Find the last prefix, which will be the longest prefix
1401 while (it.hasNext()) {
1402 intf = it.next();
1403 }
1404
1405 return intf;
1406 }
1407
Ray Milkey269ffb92014-04-03 14:43:30 -07001408 // The code below should be reimplemented after removal of Floodlight's
1409 // ITopologyService API. It should be implemented on top of network graph
1410 // notifications. (It was pretty hacky anyway...)
1411 /*
1412 @Override
1413 public void topologyChanged() {
1414 if (topologyReady) {
1415 return;
1416 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001417
Ray Milkey269ffb92014-04-03 14:43:30 -07001418 boolean refreshNeeded = false;
1419 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1420 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1421 //We don't need to recalculate anything for just link updates
1422 //They happen very frequently
1423 refreshNeeded = true;
1424 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001425
Ray Milkey269ffb92014-04-03 14:43:30 -07001426 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001427
Ray Milkey269ffb92014-04-03 14:43:30 -07001428 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1429 synchronized (linkUpdates) {
1430 linkUpdates.add(ldu);
1431 }
1432 }
1433 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001434
Ray Milkey269ffb92014-04-03 14:43:30 -07001435 if (refreshNeeded && !topologyReady){
1436 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1437 }
1438 }
1439 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001440
Ray Milkey269ffb92014-04-03 14:43:30 -07001441 @Override
1442 public void addedSwitch(IOFSwitch sw) {
1443 if (!topologyReady) {
1444 sw.clearAllFlowMods();
1445 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001446
Ray Milkey269ffb92014-04-03 14:43:30 -07001447 flowCache.switchConnected(sw);
1448 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001449
Ray Milkey269ffb92014-04-03 14:43:30 -07001450 @Override
1451 public void removedSwitch(IOFSwitch sw) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001452 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001453 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001454
Ray Milkey269ffb92014-04-03 14:43:30 -07001455 @Override
1456 public void switchPortChanged(Long switchId) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001457 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001458 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001459
Ray Milkey269ffb92014-04-03 14:43:30 -07001460 @Override
1461 public String getName() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001462 return "sdnip";
Ray Milkey269ffb92014-04-03 14:43:30 -07001463 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001464
Ray Milkey269ffb92014-04-03 14:43:30 -07001465 /*
1466 * IConfigInfoService methods
1467 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001468
Ray Milkey269ffb92014-04-03 14:43:30 -07001469 @Override
1470 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001471 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001472 return (intf != null && intf.getIpAddress().equals(address));
1473 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001474
Ray Milkey269ffb92014-04-03 14:43:30 -07001475 @Override
1476 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001477 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001478 return (intf != null && !intf.getIpAddress().equals(address));
1479 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001480
Ray Milkey269ffb92014-04-03 14:43:30 -07001481 @Override
1482 public boolean fromExternalNetwork(long inDpid, short inPort) {
1483 for (Interface intf : interfaces.values()) {
1484 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1485 return true;
1486 }
1487 }
1488 return false;
1489 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001490
Ray Milkey269ffb92014-04-03 14:43:30 -07001491 @Override
1492 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001493 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -07001494 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001495
Ray Milkey269ffb92014-04-03 14:43:30 -07001496 @Override
1497 public boolean hasLayer3Configuration() {
1498 return !interfaces.isEmpty();
1499 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001500
Ray Milkey269ffb92014-04-03 14:43:30 -07001501 @Override
1502 public MACAddress getRouterMacAddress() {
1503 return bgpdMacAddress;
1504 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001505
Ray Milkey269ffb92014-04-03 14:43:30 -07001506 @Override
1507 public short getVlan() {
1508 return vlan;
1509 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001510}