blob: 49128ea1f65083d364970bbc547bef6698986ba9 [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;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070020import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
Jonathan Hart64c0b202013-08-20 15:45:07 +120021import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080022import net.floodlightcontroller.core.module.FloodlightModuleContext;
23import net.floodlightcontroller.core.module.FloodlightModuleException;
24import net.floodlightcontroller.core.module.IFloodlightModule;
25import net.floodlightcontroller.core.module.IFloodlightService;
pingping-lina2cbfad2013-03-07 08:39:21 +080026import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120027import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0961fe82014-04-03 09:56:25 -070028import net.onrc.onos.apps.proxyarp.IArpRequester;
29import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart8f6dc092014-04-18 15:56:43 -070030import net.onrc.onos.apps.sdnip.RibUpdate.Operation;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070031import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutable;
Komal Shah399a2922014-05-28 01:57:40 -070032import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutableNew;
33import net.onrc.onos.core.intent.IntentOperation;
34import net.onrc.onos.core.intent.IntentOperationList;
35import net.onrc.onos.core.intent.ShortestPathIntent;
36import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
Jonathan Harta99ec672014-04-03 11:30:34 -070037import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070038import net.onrc.onos.core.main.config.IConfigInfoService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070039import net.onrc.onos.core.packet.Ethernet;
40import net.onrc.onos.core.packet.IPv4;
Komal Shah399a2922014-05-28 01:57:40 -070041import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart23701d12014-04-03 10:45:48 -070042import net.onrc.onos.core.util.CallerId;
43import net.onrc.onos.core.util.DataPath;
44import net.onrc.onos.core.util.Dpid;
45import net.onrc.onos.core.util.FlowEntryAction;
46import net.onrc.onos.core.util.FlowEntryActions;
47import net.onrc.onos.core.util.FlowEntryMatch;
48import net.onrc.onos.core.util.FlowId;
49import net.onrc.onos.core.util.FlowPath;
50import net.onrc.onos.core.util.FlowPathFlags;
51import net.onrc.onos.core.util.FlowPathType;
52import net.onrc.onos.core.util.FlowPathUserState;
53import net.onrc.onos.core.util.IPv4Net;
Yuta HIGUCHIfb564502014-06-16 21:29:00 -070054import net.onrc.onos.core.util.PortNumber;
Jonathan Hart23701d12014-04-03 10:45:48 -070055import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080056import net.sf.json.JSONArray;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070057import net.sf.json.JSONException;
pingping-line2a09ca2013-03-23 09:33:58 +080058import net.sf.json.JSONObject;
59import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080060
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070061import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120062import org.codehaus.jackson.JsonParseException;
63import org.codehaus.jackson.map.JsonMappingException;
64import org.codehaus.jackson.map.ObjectMapper;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070065import org.projectfloodlight.openflow.protocol.OFPortDesc;
pingping-lina2cbfad2013-03-07 08:39:21 +080066import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
Jonathan Hart4dfc3652013-08-02 20:22:36 +120069import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120070import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120071import com.google.common.collect.Multimaps;
72import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120073import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120074import com.google.common.util.concurrent.ThreadFactoryBuilder;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070075import com.googlecode.concurrenttrees.radix.RadixTree;
76import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
77import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
78import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120079
Jonathan Hart8f6dc092014-04-18 15:56:43 -070080public class SdnIp implements IFloodlightModule, ISdnIpService,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070081 IArpRequester, IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070082
Jonathan Hart8f6dc092014-04-18 15:56:43 -070083 private static final Logger log = LoggerFactory.getLogger(SdnIp.class);
Sho SHIMIZU9ec39822014-07-10 17:15:12 -070084 private final CallerId callerId = new CallerId("SDNIP");
pingping-lina2cbfad2013-03-07 08:39:21 +080085
Ray Milkey269ffb92014-04-03 14:43:30 -070086 private IFloodlightProviderService floodlightProvider;
87 private ILinkDiscoveryService linkDiscoveryService;
88 private IRestApiService restApi;
89 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070090
Jonathan Hartf6978ce2014-06-23 11:20:04 -070091 private InvertedRadixTree<RibEntry> bgpRoutes;
92 private InvertedRadixTree<Interface> interfaceRoutes;
93
Ray Milkey269ffb92014-04-03 14:43:30 -070094 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070095
Ray Milkey269ffb92014-04-03 14:43:30 -070096 private String bgpdRestIp;
97 private String routerId;
Ray Milkey5df613b2014-04-15 10:50:56 -070098 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
99 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700100
Komal Shah399a2922014-05-28 01:57:40 -0700101 /* ShortestPath Intent Variables */
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700102 private final String caller = "SdnIp";
Komal Shah399a2922014-05-28 01:57:40 -0700103 private IControllerRegistryService controllerRegistryService;
104 private IPathCalcRuntimeService pathRuntime;
105 /* Shortest Intent Path Variables */
106
Ray Milkey2476cac2014-04-08 11:03:21 -0700107 private static final short ARP_PRIORITY = 20;
Ray Milkey5d406012014-04-08 14:44:41 -0700108
Jonathan Hart938a0152014-04-07 18:27:31 -0700109 // The fields below are unused after the move to FlowManager.
110 // Remove them if no longer needed.
111 /*
112 // We need to identify our flows somehow, in lieu of an OS-wide mechanism
113 // to hand out cookie IDs to prevent conflicts.
114 private static final long APP_COOKIE = 0xa0000000000000L;
115 // Cookie for flows that do L2 forwarding within SDN domain to egress routers
116 private static final long L2_FWD_COOKIE = APP_COOKIE + 1;
117 // Cookie for flows in ingress switches that rewrite the MAC address
118 private static final long MAC_RW_COOKIE = APP_COOKIE + 2;
119 // Cookie for flows that setup BGP paths
120 private static final long BGP_COOKIE = APP_COOKIE + 3;
121 // Forwarding uses priority 0, and the mac rewrite entries in ingress switches
122 // need to be higher priority than this otherwise the rewrite may not get done
123 private static final short SDNIP_PRIORITY = 10;
124 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700125
Ray Milkey2476cac2014-04-08 11:03:21 -0700126 private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700127
Jonathan Hart938a0152014-04-07 18:27:31 -0700128 private static final int TOPO_DETECTION_WAIT = 2; // seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700129
Jonathan Hart938a0152014-04-07 18:27:31 -0700130 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700131 private List<String> switches;
132 private Map<String, Interface> interfaces;
133 private Map<InetAddress, BgpPeer> bgpPeers;
134 private SwitchPort bgpdAttachmentPoint;
135 private MACAddress bgpdMacAddress;
136 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700137
Jonathan Hart938a0152014-04-07 18:27:31 -0700138 // True when all switches have connected
Ray Milkey269ffb92014-04-03 14:43:30 -0700139 private volatile boolean switchesConnected = false;
Jonathan Hart938a0152014-04-07 18:27:31 -0700140 // True when we have a full mesh of shortest paths between gateways
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200142
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700143 // private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700144
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700146
Ray Milkey269ffb92014-04-03 14:43:30 -0700147 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700148
Ray Milkey269ffb92014-04-03 14:43:30 -0700149 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700150
Ray Milkey269ffb92014-04-03 14:43:30 -0700151 private Map<InetAddress, Path> pushedPaths;
152 private Map<Prefix, Path> prefixToPath;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700153 // private Multimap<Prefix, PushedFlowMod> pushedFlows;
Ray Milkey269ffb92014-04-03 14:43:30 -0700154 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700155
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700156 // XXX FlowCache has been removed
157 //private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700158
Ray Milkey269ffb92014-04-03 14:43:30 -0700159 // TODO: Fix for the new Topology Network Graph
160 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700161
Jonathan Hart284e70f2014-07-05 12:32:51 -0700162 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700163 private class TopologyChangeDetector implements Runnable {
164 @Override
165 public void run() {
166 log.debug("Running topology change detection task");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700167 // TODO: Fix the code below after topoLinkService was removed
Ray Milkey269ffb92014-04-03 14:43:30 -0700168 synchronized (linkUpdates) {
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700169
Ray Milkey269ffb92014-04-03 14:43:30 -0700170 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700171
Ray Milkey269ffb92014-04-03 14:43:30 -0700172 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700173
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 Iterator<LDUpdate> it = linkUpdates.iterator();
175 while (it.hasNext()){
176 LDUpdate ldu = it.next();
177 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
178 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700179
Ray Milkey269ffb92014-04-03 14:43:30 -0700180 if (activeLinks.contains(l)){
181 it.remove();
182 }
183 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700184 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700185
Ray Milkey269ffb92014-04-03 14:43:30 -0700186 if (!topologyReady) {
187 if (linkUpdates.isEmpty()) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700188 // All updates have been seen in network map.
189 // We can check if topology is ready
Ray Milkey269ffb92014-04-03 14:43:30 -0700190 log.debug("No known changes outstanding. Checking topology now");
191 checkStatus();
192 } else {
Jonathan Hart938a0152014-04-07 18:27:31 -0700193 // We know of some link updates that haven't propagated to the database yet
Ray Milkey269ffb92014-04-03 14:43:30 -0700194 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
195 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
196 }
197 }
198 }
199 }
Jonathan Hart284e70f2014-07-05 12:32:51 -0700200 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700201
Ray Milkey269ffb92014-04-03 14:43:30 -0700202 private void readConfiguration(String configFilename) {
203 File gatewaysFile = new File(configFilename);
204 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700205
Ray Milkey269ffb92014-04-03 14:43:30 -0700206 try {
207 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700208
Ray Milkey269ffb92014-04-03 14:43:30 -0700209 switches = config.getSwitches();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700210 interfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700211 for (Interface intf : config.getInterfaces()) {
212 interfaces.put(intf.getName(), intf);
213 }
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700214 bgpPeers = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700215 for (BgpPeer peer : config.getPeers()) {
216 bgpPeers.put(peer.getIpAddress(), peer);
217 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700218
Ray Milkey269ffb92014-04-03 14:43:30 -0700219 bgpdAttachmentPoint = new SwitchPort(
220 new Dpid(config.getBgpdAttachmentDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700221 new PortNumber(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700222
Ray Milkey269ffb92014-04-03 14:43:30 -0700223 bgpdMacAddress = config.getBgpdMacAddress();
224 vlan = config.getVlan();
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -0700225 } catch (JsonParseException | JsonMappingException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700226 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700227 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700228 } catch (IOException e) {
229 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700230 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700231 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700232
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700233 // Populate the interface Patricia Tree
Ray Milkey269ffb92014-04-03 14:43:30 -0700234 for (Interface intf : interfaces.values()) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700235 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
236 intf.getPrefixLength());
237 interfaceRoutes.put(prefix.toBinaryString(), intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700238 }
239 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700240
Ray Milkey269ffb92014-04-03 14:43:30 -0700241 @Override
242 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700243 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700244 l.add(ISdnIpService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700245 l.add(IConfigInfoService.class);
246 return l;
247 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700248
Ray Milkey269ffb92014-04-03 14:43:30 -0700249 @Override
250 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700251 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700252 m.put(ISdnIpService.class, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700253 m.put(IConfigInfoService.class, this);
254 return m;
255 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800256
Ray Milkey269ffb92014-04-03 14:43:30 -0700257 @Override
258 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700259 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700260 l.add(IFloodlightProviderService.class);
261 l.add(IRestApiService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700262 l.add(IControllerRegistryService.class);
263 l.add(IPathCalcRuntimeService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700264 return l;
265 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700266
Ray Milkey269ffb92014-04-03 14:43:30 -0700267 @Override
268 public void init(FloodlightModuleContext context)
269 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700270
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700271 bgpRoutes = new ConcurrentInvertedRadixTree<>(
272 new DefaultByteArrayNodeFactory());
273 interfaceRoutes = new ConcurrentInvertedRadixTree<>(
274 new DefaultByteArrayNodeFactory());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700275
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700276 ribUpdates = new LinkedBlockingQueue<>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700277
Ray Milkey269ffb92014-04-03 14:43:30 -0700278 // Register floodlight provider and REST handler.
279 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
280 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
281 restApi = context.getServiceImpl(IRestApiService.class);
282 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800283
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700284 controllerRegistryService = context
285 .getServiceImpl(IControllerRegistryService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700286 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700287
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700288 // ScheduledExecutorService executor =
289 // Executors.newScheduledThreadPool(1);
290 // topologyChangeDetectorTask = new SingletonTask(executor, new
291 // TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700292
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700293 pathsWaitingOnArp = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700294 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
295 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700296
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700297 pushedPaths = new HashMap<>();
298 prefixToPath = new HashMap<>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700299 // pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700300 pushedFlowIds = HashMultimap.create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700301
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700302 //flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700303
Ray Milkey269ffb92014-04-03 14:43:30 -0700304 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
305 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700306
Jonathan Hart938a0152014-04-07 18:27:31 -0700307 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700308 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
309 if (bgpdRestIp == null) {
310 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700311 throw new ConfigurationRuntimeException(
312 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700313 } else {
314 log.info("BgpdRestIp set to {}", bgpdRestIp);
315 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700316
Ray Milkey269ffb92014-04-03 14:43:30 -0700317 routerId = context.getConfigParams(this).get("RouterId");
318 if (routerId == null) {
319 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700320 throw new ConfigurationRuntimeException(
321 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700322 } else {
323 log.info("RouterId set to {}", routerId);
324 }
pingping-linba5c52f2014-02-11 16:52:01 -0800325
Ray Milkey269ffb92014-04-03 14:43:30 -0700326 String configFilenameParameter = context.getConfigParams(this).get("configfile");
327 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700328 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700329 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700330 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700331
Ray Milkey5df613b2014-04-15 10:50:56 -0700332 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700333 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700334
Ray Milkey269ffb92014-04-03 14:43:30 -0700335 @Override
336 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700337 restApi.addRestletRoutable(new SdnIpWebRoutable());
Komal Shah399a2922014-05-28 01:57:40 -0700338 restApi.addRestletRoutable(new SdnIpWebRoutableNew());
Ray Milkey269ffb92014-04-03 14:43:30 -0700339 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800340
Jonathan Hart938a0152014-04-07 18:27:31 -0700341 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700342 retrieveRib();
343 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800344
Ray Milkey269ffb92014-04-03 14:43:30 -0700345 @Override
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700346 public RadixTree<RibEntry> getPtree() {
347 return bgpRoutes;
Ray Milkey269ffb92014-04-03 14:43:30 -0700348 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700349
Ray Milkey269ffb92014-04-03 14:43:30 -0700350 @Override
351 public void clearPtree() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700352 log.warn("Clear table operation not supported");
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
Jonathan Hart31e15f12014-04-10 10:33:00 -0700356 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700357 return bgpdRestIp;
358 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700359
Ray Milkey269ffb92014-04-03 14:43:30 -0700360 @Override
361 public String getRouterId() {
362 return routerId;
363 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700364
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 private void retrieveRib() {
366 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
367 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700368
Jonathan Hart938a0152014-04-07 18:27:31 -0700369 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700370 return;
371 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700372
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700373 try {
374 response = response.replaceAll("\"", "'");
375 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
376 JSONArray ribArray = jsonObj.getJSONArray("rib");
377 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700378
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700379 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700380
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700381 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700382
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700383 for (int j = 0; j < size; j++) {
384 JSONObject ribEntry = ribArray.getJSONObject(j);
385 String prefix = ribEntry.getString("prefix");
386 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700387
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700388 // Insert each rib entry into the local rib
389 String[] substring = prefix.split("/");
390 String prefix1 = substring[0];
391 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700392
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700393 Prefix p;
394 try {
395 p = new Prefix(prefix1, Integer.parseInt(mask1));
396 } catch (NumberFormatException e) {
397 log.warn("Wrong mask format in RIB JSON: {}", mask1);
398 continue;
399 } catch (IllegalArgumentException e1) {
400 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
401 continue;
402 }
403
404 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
405
406 try {
407 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
408 } catch (InterruptedException e) {
409 log.debug("Interrupted while pushing onto update queue");
410 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700411 }
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700412 } catch (JSONException e) {
413 // TODO don't parse JSON manually
414 log.error("Error parsing inital route table JSON:", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700415 }
416 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700417
Ray Milkey269ffb92014-04-03 14:43:30 -0700418 @Override
419 public void newRibUpdate(RibUpdate update) {
420 try {
421 ribUpdates.put(update);
422 } catch (InterruptedException e) {
423 log.debug("Interrupted while putting on ribUpdates queue", e);
424 Thread.currentThread().interrupt();
425 }
426 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700427
Sho SHIMIZUba372192014-07-10 08:59:57 -0700428 private void processRibAdd(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700429 synchronized (this) {
430 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700431
Jonathan Hart938a0152014-04-07 18:27:31 -0700432 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700433
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700434 RibEntry rib = bgpRoutes.put(prefix.toBinaryString(), update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700435
Jonathan Hart938a0152014-04-07 18:27:31 -0700436 if (rib != null && !rib.equals(update.getRibEntry())) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700437 // There was an existing nexthop for this prefix. This update
438 // supersedes that,
439 // so we need to remove the old flows for this prefix from the
440 // switches
Ray Milkey7531a342014-04-11 15:08:12 -0700441 executeDeletePrefix(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700442 }
Ray Milkey5d406012014-04-08 14:44:41 -0700443
Jonathan Hart938a0152014-04-07 18:27:31 -0700444 if (update.getRibEntry().getNextHop().equals(
445 InetAddresses.forString("0.0.0.0"))) {
446 // Route originated by SDN domain
447 // We don't handle these at the moment
448 log.debug("Own route {} to {}", prefix,
449 update.getRibEntry().getNextHop().getHostAddress());
450 return;
451 }
Ray Milkey5d406012014-04-08 14:44:41 -0700452
Ray Milkey7531a342014-04-11 15:08:12 -0700453 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700454 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700455 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700456
Ray Milkey7531a342014-04-11 15:08:12 -0700457 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700458 // TODO: Fix the code below. Note that "deviceStorage" was removed.
459
460 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700461 Prefix prefix = update.getPrefix();
462 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700463
Ray Milkey269ffb92014-04-03 14:43:30 -0700464 InetAddress dstIpAddress = rib.getNextHop();
465 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800466
Ray Milkey269ffb92014-04-03 14:43:30 -0700467 // See if we know the MAC address of the next hop
468 // 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 -0700469 IDeviceObject nextHopDevice =
470 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700471
Ray Milkey269ffb92014-04-03 14:43:30 -0700472 if (nextHopDevice == null){
473 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
474 prefixesWaitingOnArp.put(dstIpAddress,
475 new RibUpdate(Operation.UPDATE, prefix, rib));
476 proxyArp.sendArpRequest(dstIpAddress, this, true);
477 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800478
Ray Milkey269ffb92014-04-03 14:43:30 -0700479 }
480 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700481
Ray Milkey269ffb92014-04-03 14:43:30 -0700482 // Find the attachment point (egress interface) of the next hop
483 Interface egressInterface = null;
484 if (bgpPeers.containsKey(dstIpAddress)) {
485 //Route to a peer
486 log.debug("Route to peer {}", dstIpAddress);
487 BgpPeer peer = bgpPeers.get(dstIpAddress);
488 egressInterface = interfaces.get(peer.getInterfaceName());
489 } else {
490 //Route to non-peer
491 log.debug("Route to non-peer {}", dstIpAddress);
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700492 egressInterface = interfacePtree.match(
Ray Milkey269ffb92014-04-03 14:43:30 -0700493 new Prefix(dstIpAddress.getAddress(), 32));
494 if (egressInterface == null) {
495 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
496 return;
497 }
498 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700499
Ray Milkey269ffb92014-04-03 14:43:30 -0700500 if (nextHopMacAddress == null) {
501 prefixesWaitingOnArp.put(dstIpAddress,
502 new RibUpdate(Operation.UPDATE, prefix, rib));
503 proxyArp.sendArpRequest(dstIpAddress, this, true);
504 return;
505 } else {
506 if (!bgpPeers.containsKey(dstIpAddress)) {
507 //If the prefix is for a non-peer we need to ensure there's a path,
508 //and push one if there isn't.
509 Path path = pushedPaths.get(dstIpAddress);
510 if (path == null) {
511 path = new Path(egressInterface, dstIpAddress);
512 calculateAndPushPath(path, nextHopMacAddress);
513 pushedPaths.put(dstIpAddress, path);
514 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700515
Ray Milkey269ffb92014-04-03 14:43:30 -0700516 path.incrementUsers();
517 prefixToPath.put(prefix, path);
518 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700519
Ray Milkey269ffb92014-04-03 14:43:30 -0700520 //For all prefixes we need to add the first-hop mac-rewriting flows
521 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
522 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700523 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700524 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700525
Ray Milkey269ffb92014-04-03 14:43:30 -0700526 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700527 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix to
528 * all other border switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700529 */
530 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700531 MACAddress nextHopMacAddress) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700532 log.debug("Adding flows for prefix {}, next hop mac {}",
533 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700534
Ray Milkey269ffb92014-04-03 14:43:30 -0700535 FlowPath flowPath = new FlowPath();
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700536 flowPath.setInstallerId(callerId);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700537
Ray Milkey269ffb92014-04-03 14:43:30 -0700538 // Set flowPath FlowPathType and FlowPathUserState
539 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
540 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800541
Ray Milkey269ffb92014-04-03 14:43:30 -0700542 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
543 // only to the first-host switches
544 FlowPathFlags flowPathFlags = new FlowPathFlags();
545 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
546 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800547
Ray Milkey269ffb92014-04-03 14:43:30 -0700548 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700549 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700550 new SwitchPort(new Dpid(egressInterface.getDpid()),
551 new PortNumber(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800552
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700553 // We only need one flow mod per switch, so pick one interface on each
554 // switch
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700555 Map<Long, Interface> srcInterfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700556 for (Interface intf : interfaces.values()) {
557 if (!srcInterfaces.containsKey(intf.getDpid())
558 && !intf.equals(egressInterface)) {
559 srcInterfaces.put(intf.getDpid(), intf);
560 }
561 }
562 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800563
Ray Milkey269ffb92014-04-03 14:43:30 -0700564 if (egressInterface.equals(srcInterface)) {
565 continue;
566 }
pingping-linba5c52f2014-02-11 16:52:01 -0800567
Ray Milkey269ffb92014-04-03 14:43:30 -0700568 // Create flowPath FlowId
569 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800570
Ray Milkey269ffb92014-04-03 14:43:30 -0700571 // Create DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700572 SwitchPort srcPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700573 new SwitchPort(new Dpid(srcInterface.getDpid()),
574 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800575
Ray Milkey269ffb92014-04-03 14:43:30 -0700576 DataPath dataPath = new DataPath();
577 dataPath.setSrcPort(srcPort);
578 dataPath.setDstPort(dstPort);
579 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800580
Ray Milkey269ffb92014-04-03 14:43:30 -0700581 // Create flow path matching condition(s): IPv4 Prefix
582 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700583 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700584 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
585 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
586 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300587
Ray Milkey269ffb92014-04-03 14:43:30 -0700588 /*
589 * Create the Flow Entry Action(s): dst-MAC rewrite action
590 */
591 FlowEntryActions flowEntryActions = new FlowEntryActions();
592 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
593 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
594 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
595 flowEntryActions.addAction(flowEntryAction1);
596 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800597
Ray Milkey269ffb92014-04-03 14:43:30 -0700598 // Flow Path installation, only to first hop switches
599 // TODO: Add the flow by using the new Path Intent framework
600 /*
601 if (flowManagerService.addFlow(flowPath) == null) {
602 log.error("Failed to install flow path to the first hop for " +
603 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
604 nextHopMacAddress);
605 }
606 else {
607 log.debug("Successfully installed flow path to the first hop " +
608 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
609 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800610
Ray Milkey269ffb92014-04-03 14:43:30 -0700611 pushedFlowIds.put(prefix, flowPath.flowId());
612 }
613 */
614 }
615 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700616
Sho SHIMIZUba372192014-07-10 08:59:57 -0700617 private void processRibDelete(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700618 synchronized (this) {
619 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700620
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700621 // if (ptree.remove(prefix, update.getRibEntry())) {
622 // TODO check the change of logic here - remove doesn't check that
623 // the
624 // rib entry was what we expected (and we can't do this
625 // concurrently)
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700626 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) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700647 // 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
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700710 // TODO test next-hop changes
711 // TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800712
Ray Milkey269ffb92014-04-03 14:43:30 -0700713 /**
714 * On startup, we need to calculate a full mesh of paths between all gateway
Ray Milkeyb41100a2014-04-10 10:42:15 -0700715 * switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700716 */
717 private void setupFullMesh() {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700718 // TODO: Fix the code below. Note that "deviceStorage" was removed.
719
720 /*
721
Ray Milkey269ffb92014-04-03 14:43:30 -0700722 //For each border router, calculate and install a path from every other
723 //border switch to said border router. However, don't install the entry
724 //in to the first hop switch, as we need to install an entry to rewrite
725 //for each prefix received. This will be done later when prefixes have
726 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700727
Ray Milkey269ffb92014-04-03 14:43:30 -0700728 for (BgpPeer peer : bgpPeers.values()) {
729 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700730
Ray Milkey269ffb92014-04-03 14:43:30 -0700731 //We know there's not already a Path here pushed, because this is
732 //called before all other routing
733 Path path = new Path(peerInterface, peer.getIpAddress());
734 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700735
Ray Milkey269ffb92014-04-03 14:43:30 -0700736 //See if we know the MAC address of the peer. If not we can't
737 //do anything until we learn it
Ray Milkey269ffb92014-04-03 14:43:30 -0700738 MACAddress macAddress = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700739 IDeviceObject nextHopDevice =
740 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800741
Ray Milkey269ffb92014-04-03 14:43:30 -0700742 if(nextHopDevice == null){
743 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
744 //Put in the pending paths list first
745 pathsWaitingOnArp.put(peer.getIpAddress(), path);
746 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
747 continue;
748 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700749
Ray Milkey269ffb92014-04-03 14:43:30 -0700750 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
pingping-linba5c52f2014-02-11 16:52:01 -0800751
Ray Milkey269ffb92014-04-03 14:43:30 -0700752 if (macAddress == null) {
753 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
754 //Put in the pending paths list first
755 pathsWaitingOnArp.put(peer.getIpAddress(), path);
756 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
757 continue;
758 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700759
Ray Milkey269ffb92014-04-03 14:43:30 -0700760 //If we know the MAC, lets go ahead and push the paths to this peer
761 calculateAndPushPath(path, macAddress);
762 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700763 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700764 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700765
Ray Milkey269ffb92014-04-03 14:43:30 -0700766 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
767 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700768
Ray Milkey269ffb92014-04-03 14:43:30 -0700769 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
770 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800771
Ray Milkey269ffb92014-04-03 14:43:30 -0700772 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800773
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700774 flowPath.setInstallerId(callerId);
pingping-linba5c52f2014-02-11 16:52:01 -0800775
Ray Milkey269ffb92014-04-03 14:43:30 -0700776 // Set flowPath FlowPathType and FlowPathUserState
777 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
778 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800779
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700780 // Insert the dest-mac based forwarding flow entry to the non-first-hop
781 // switches
Ray Milkey269ffb92014-04-03 14:43:30 -0700782 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 =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700788 new SwitchPort(new Dpid(dstInterface.getDpid()),
789 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 =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700802 new SwitchPort(new Dpid(srcInterface.getDpid()),
803 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
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700817 // Shortest Path Flow, and is always the last action for the Flow
818 // Entries
Ray Milkey269ffb92014-04-03 14:43:30 -0700819 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
820 // TODO: Add the flow by using the new Path Intent framework
821 /*
822 if (flowManagerService.addFlow(flowPath) == null) {
823 log.error("Failed to set up MAC based forwarding path to {}, {}",
824 path.getDstIpAddress().getHostAddress(),dstMacAddress);
825 }
826 else {
827 log.debug("Successfully set up MAC based forwarding path to {}, {}",
828 path.getDstIpAddress().getHostAddress(),dstMacAddress);
829 }
830 */
831 }
832 }
pingping-linba5c52f2014-02-11 16:52:01 -0800833
Komal Shah399a2922014-05-28 01:57:40 -0700834 @Override
835 public void beginRoutingNew() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700836 setupBgpPathsNew();
Komal Shah399a2922014-05-28 01:57:40 -0700837
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700838 // setupFullMesh();
Komal Shah399a2922014-05-28 01:57:40 -0700839
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700840 // Suppress link discovery on external-facing router ports
Komal Shah399a2922014-05-28 01:57:40 -0700841
842 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -0700843 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Komal Shah399a2922014-05-28 01:57:40 -0700844 }
845
846 bgpUpdatesExecutor.execute(new Runnable() {
847 @Override
848 public void run() {
849 doUpdatesThread();
850 }
851 });
852 }
853
Ray Milkey269ffb92014-04-03 14:43:30 -0700854 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700855 * Setup the Paths to the BGP Daemon. Run a loop for all of the bgpPeers
856 * Push flow from BGPd to the peer Push flow from peer to BGPd Parameters to
857 * pass to the intent are as follows: String id, long srcSwitch, long
858 * srcPort, long srcMac, int srcIP, long dstSwitch, long dstPort, long
859 * dstMac, int dstIP
Komal Shah399a2922014-05-28 01:57:40 -0700860 */
861 private void setupBgpPathsNew() {
862 IntentOperationList operations = new IntentOperationList();
863 for (BgpPeer bgpPeer : bgpPeers.values()) {
864 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700865 // Inet4Address.
Komal Shah399a2922014-05-28 01:57:40 -0700866 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
867 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700868 String fwdIntentId = caller + ":"
869 + controllerRegistryService.getNextUniqueId();
870 String bwdIntentId = caller + ":"
871 + controllerRegistryService.getNextUniqueId();
Komal Shah399a2922014-05-28 01:57:40 -0700872 SwitchPort srcPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700873 new SwitchPort(bgpdAttachmentPoint.dpid(),
874 bgpdAttachmentPoint.port());
Komal Shah399a2922014-05-28 01:57:40 -0700875 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700876 new SwitchPort(new Dpid(peerInterface.getDpid()),
877 new PortNumber(peerInterface.getSwitchPort().port()));
Komal Shah399a2922014-05-28 01:57:40 -0700878 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700879 srcPort.dpid().value(), srcPort.port().value(),
880 ShortestPathIntent.EMPTYMACADDRESS, srcIP,
881 dstPort.dpid().value(), dstPort.port().value(),
882 ShortestPathIntent.EMPTYMACADDRESS, dstIP);
Komal Shah399a2922014-05-28 01:57:40 -0700883 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700884 dstPort.dpid().value(), dstPort.port().value(),
885 ShortestPathIntent.EMPTYMACADDRESS, dstIP,
886 srcPort.dpid().value(), srcPort.port().value(),
887 ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700888 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
889 operations.add(operator, fwdIntent);
890 operations.add(operator, bwdIntent);
891 }
892 pathRuntime.executeIntentOperations(operations);
893 }
894
895 /*
Jonathan Hart938a0152014-04-07 18:27:31 -0700896 * Proactively install all BGP traffic paths from BGP host attachment point
Ray Milkeyb41100a2014-04-10 10:42:15 -0700897 * in SDN network to all the virtual gateways to BGP peers in other networks.
Ray Milkey269ffb92014-04-03 14:43:30 -0700898 */
899 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200900
Ray Milkey269ffb92014-04-03 14:43:30 -0700901 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800902
Ray Milkey269ffb92014-04-03 14:43:30 -0700903 FlowPath flowPath = new FlowPath();
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700904 flowPath.setInstallerId(callerId);
pingping-linba5c52f2014-02-11 16:52:01 -0800905
Ray Milkey269ffb92014-04-03 14:43:30 -0700906 // Set flowPath FlowPathType and FlowPathUserState
907 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
908 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800909
Ray Milkey269ffb92014-04-03 14:43:30 -0700910 // Install flow paths between BGPd and its peers
911 // There is no need to set the FlowPathFlags
912 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800913
Ray Milkey269ffb92014-04-03 14:43:30 -0700914 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Ray Milkey269ffb92014-04-03 14:43:30 -0700915 // Create the Flow Path Match condition(s)
916 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700917 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
pingping-linba5c52f2014-02-11 16:52:01 -0800918
Ray Milkey269ffb92014-04-03 14:43:30 -0700919 // Match both source address and dest address
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700920 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress()
921 + "/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
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700925 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress()
926 .getHostAddress() + "/32");
Ray Milkey269ffb92014-04-03 14:43:30 -0700927 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800928
Ray Milkey269ffb92014-04-03 14:43:30 -0700929 // Match TCP protocol
930 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800931
Ray Milkey269ffb92014-04-03 14:43:30 -0700932 // Match destination TCP port
933 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
934 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800935
Ray Milkey269ffb92014-04-03 14:43:30 -0700936 /**
937 * Create the DataPath: BGP -> BGP peer
938 */
939 // Flow path for src-TCP-port
940 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800941
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700942 SwitchPort srcPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700943 new SwitchPort(bgpdAttachmentPoint.dpid(),
944 bgpdAttachmentPoint.port());
Ray Milkey269ffb92014-04-03 14:43:30 -0700945 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800946
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700947 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700948 new SwitchPort(new Dpid(peerInterface.getDpid()),
949 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700950 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800951
Ray Milkey269ffb92014-04-03 14:43:30 -0700952 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800953
Ray Milkey269ffb92014-04-03 14:43:30 -0700954 // TODO: Add the flow by using the new Path Intent framework
955 /*
956 if (flowManagerService.addFlow(flowPath) == null) {
957 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
958 bgpPeer.getIpAddress().getHostAddress());
959 }
960 else {
961 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
962 bgpPeer.getIpAddress().getHostAddress());
963 }
964 */
pingping-linba5c52f2014-02-11 16:52:01 -0800965
Ray Milkey269ffb92014-04-03 14:43:30 -0700966 // Disable dst-TCP-port, and set src-TCP-port
967 flowEntryMatch.disableDstTcpUdpPort();
968 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
969 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800970
Ray Milkey269ffb92014-04-03 14:43:30 -0700971 // Create a new FlowId
972 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800973
Ray Milkey269ffb92014-04-03 14:43:30 -0700974 // TODO: Add the flow by using the new Path Intent framework
975 /*
976 if (flowManagerService.addFlow(flowPath) == null) {
977 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
978 bgpPeer.getIpAddress().getHostAddress());
979 }
980 else {
981 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
982 bgpPeer.getIpAddress().getHostAddress());
983 }
984 */
pingping-linba5c52f2014-02-11 16:52:01 -0800985
Ray Milkey269ffb92014-04-03 14:43:30 -0700986 /**
987 * Create the DataPath: BGP <-BGP peer
988 */
989 // Reversed BGP flow path for src-TCP-port
990 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800991
Ray Milkey2476cac2014-04-08 11:03:21 -0700992 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800993
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700994 SwitchPort reverseDstPort =
Komal Shah399a2922014-05-28 01:57:40 -0700995 new SwitchPort(bgpdAttachmentPoint.dpid(),
996 bgpdAttachmentPoint.port());
Ray Milkey2476cac2014-04-08 11:03:21 -0700997 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800998
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700999 SwitchPort reverseSrcPort =
Komal Shah399a2922014-05-28 01:57:40 -07001000 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -07001001 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey2476cac2014-04-08 11:03:21 -07001002 reverseDataPath.setSrcPort(reverseSrcPort);
1003 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001004
Jonathan Hart938a0152014-04-07 18:27:31 -07001005 // Reverse the dst IP and src IP addresses
Ray Milkey269ffb92014-04-03 14:43:30 -07001006 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
1007 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
1008 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001009
Ray Milkey269ffb92014-04-03 14:43:30 -07001010 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001011
Ray Milkey269ffb92014-04-03 14:43:30 -07001012 // TODO: Add the flow by using the new Path Intent framework
1013 /*
1014 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001015
Ray Milkey269ffb92014-04-03 14:43:30 -07001016 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
1017 bgpPeer.getIpAddress().getHostAddress());
1018 }
1019 else {
1020 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
1021 bgpPeer.getIpAddress().getHostAddress());
1022 }
1023 */
pingping-linba5c52f2014-02-11 16:52:01 -08001024
Ray Milkey269ffb92014-04-03 14:43:30 -07001025 // Reversed BGP flow path for dst-TCP-port
1026 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001027
Ray Milkey269ffb92014-04-03 14:43:30 -07001028 // Disable src-TCP-port, and set the dst-TCP-port
1029 flowEntryMatch.disableSrcTcpUdpPort();
1030 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
1031 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001032
Ray Milkey269ffb92014-04-03 14:43:30 -07001033 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001034
Ray Milkey269ffb92014-04-03 14:43:30 -07001035 // TODO: Add the flow by using the new Path Intent framework
1036 /*
1037 if (flowManagerService.addFlow(flowPath) == null) {
1038 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1039 bgpPeer.getIpAddress().getHostAddress());
1040 }
1041 else {
1042 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1043 bgpPeer.getIpAddress().getHostAddress());
1044 }
1045 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001046
Ray Milkey269ffb92014-04-03 14:43:30 -07001047 /**
1048 * ICMP paths between BGPd and its peers
1049 */
Jonathan Hart938a0152014-04-07 18:27:31 -07001050 // match ICMP protocol BGP <- Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001051 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001052
Ray Milkey269ffb92014-04-03 14:43:30 -07001053 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
1054 flowEntryMatch.disableSrcTcpUdpPort();
1055 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -08001056
Ray Milkey269ffb92014-04-03 14:43:30 -07001057 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001058
Ray Milkey2476cac2014-04-08 11:03:21 -07001059 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001060
Ray Milkey269ffb92014-04-03 14:43:30 -07001061 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001062
Ray Milkey269ffb92014-04-03 14:43:30 -07001063 // TODO: Add the flow by using the new Path Intent framework
1064 /*
1065 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001066
Ray Milkey269ffb92014-04-03 14:43:30 -07001067 log.error("Failed to set up ICMP path BGP <- Peer {}",
1068 bgpPeer.getIpAddress().getHostAddress());
1069 }
1070 else {
1071 log.debug("Successfully set up ICMP path BGP <- Peer {}",
1072 bgpPeer.getIpAddress().getHostAddress());
1073 }
1074 */
pingping-linba5c52f2014-02-11 16:52:01 -08001075
Jonathan Hart938a0152014-04-07 18:27:31 -07001076 // match ICMP protocol BGP -> Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001077 flowPath.setFlowId(new FlowId());
Ray Milkey269ffb92014-04-03 14:43:30 -07001078 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
1079 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
1080 flowPath.setFlowEntryMatch(flowEntryMatch);
Ray Milkey269ffb92014-04-03 14:43:30 -07001081 flowPath.setDataPath(dataPath);
Ray Milkey269ffb92014-04-03 14:43:30 -07001082 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001083
Ray Milkey269ffb92014-04-03 14:43:30 -07001084 // TODO: Add the flow by using the new Path Intent framework
1085 /*
1086 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001087
Ray Milkey269ffb92014-04-03 14:43:30 -07001088 log.error("Failed to set up ICMP path BGP -> Peer {}",
1089 bgpPeer.getIpAddress().getHostAddress());
1090 }
1091 else {
1092 log.debug("Successfully set up ICMP path BGP -> Peer {}",
1093 bgpPeer.getIpAddress().getHostAddress());
1094 }
1095 */
1096 }
1097 }
pingping-linba5c52f2014-02-11 16:52:01 -08001098
Ray Milkey269ffb92014-04-03 14:43:30 -07001099 @Override
1100 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
1101 log.debug("Received ARP response: {} => {}",
1102 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001103
Ray Milkey269ffb92014-04-03 14:43:30 -07001104 /*
1105 * We synchronize on this to prevent changes to the ptree while we're pushing
1106 * flows to the switches. If the ptree changes, the ptree and switches
1107 * could get out of sync.
1108 */
1109 synchronized (this) {
1110 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001111
Ray Milkey269ffb92014-04-03 14:43:30 -07001112 if (path != null) {
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -07001113 log.debug("Pushing path to {} at {} on {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001114 path.getDstIpAddress().getHostAddress(), macAddress,
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -07001115 path.getDstInterface().getSwitchPort());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001116 // These paths should always be to BGP peers. Paths to non-peers
1117 // are
Jonathan Hart938a0152014-04-07 18:27:31 -07001118 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -07001119 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001120 // A path already got pushed to this endpoint while we were
1121 // waiting
1122 // for ARP. We'll copy over the permanent attribute if it is
1123 // set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -07001124 if (path.isPermanent()) {
1125 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1126 }
1127 } else {
1128 calculateAndPushPath(path, macAddress);
1129 pushedPaths.put(path.getDstIpAddress(), path);
1130 }
1131 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001132
Ray Milkey269ffb92014-04-03 14:43:30 -07001133 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001134
Ray Milkey269ffb92014-04-03 14:43:30 -07001135 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001136 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001137
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001138 RibEntry rib = bgpRoutes.getValueForExactKey(
1139 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -07001140 if (rib != null && rib.equals(update.getRibEntry())) {
1141 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1142 rib.getNextHop().getHostAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001143 // We only push prefix flows if the prefix is still in the
1144 // ptree
1145 // and the next hop is the same as our update. The prefix
1146 // could
1147 // have been removed while we were waiting for the ARP, or
1148 // the
Jonathan Hart938a0152014-04-07 18:27:31 -07001149 // next hop could have changed.
Ray Milkey7531a342014-04-11 15:08:12 -07001150 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -07001151 } else {
1152 log.debug("Received ARP response, but {},{} is no longer in ptree",
1153 update.getPrefix(), update.getRibEntry());
1154 }
1155 }
1156 }
1157 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001158
Jonathan Hartc78b8f62014-08-07 22:31:09 -07001159 // XXX OpenFlow message classes have been removed
1160 /*private void setupArpFlows() {
Ray Milkey269ffb92014-04-03 14:43:30 -07001161 OFMatch match = new OFMatch();
1162 match.setDataLayerType(Ethernet.TYPE_ARP);
1163 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001164
Ray Milkey269ffb92014-04-03 14:43:30 -07001165 OFFlowMod fm = new OFFlowMod();
1166 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001167
Ray Milkey269ffb92014-04-03 14:43:30 -07001168 OFActionOutput action = new OFActionOutput();
1169 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1170 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001171 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -07001172 actions.add(action);
1173 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001174
Ray Milkey269ffb92014-04-03 14:43:30 -07001175 fm.setIdleTimeout((short) 0)
1176 .setHardTimeout((short) 0)
1177 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1178 .setCookie(0)
1179 .setCommand(OFFlowMod.OFPFC_ADD)
1180 .setPriority(ARP_PRIORITY)
1181 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001182
Ray Milkey269ffb92014-04-03 14:43:30 -07001183 for (String strdpid : switches) {
1184 flowCache.write(HexString.toLong(strdpid), fm);
1185 }
1186 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001187
Ray Milkey269ffb92014-04-03 14:43:30 -07001188 private void setupDefaultDropFlows() {
1189 OFFlowMod fm = new OFFlowMod();
1190 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -07001191 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001192
Ray Milkey269ffb92014-04-03 14:43:30 -07001193 fm.setIdleTimeout((short) 0)
1194 .setHardTimeout((short) 0)
1195 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1196 .setCookie(0)
1197 .setCommand(OFFlowMod.OFPFC_ADD)
1198 .setPriority((short) 0)
1199 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001200
Ray Milkey269ffb92014-04-03 14:43:30 -07001201 OFFlowMod fmLLDP;
1202 OFFlowMod fmBDDP;
1203 try {
1204 fmLLDP = fm.clone();
1205 fmBDDP = fm.clone();
1206 } catch (CloneNotSupportedException e1) {
1207 log.error("Error cloning flow mod", e1);
1208 return;
1209 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001210
Ray Milkey269ffb92014-04-03 14:43:30 -07001211 OFMatch matchLLDP = new OFMatch();
1212 matchLLDP.setDataLayerType((short) 0x88cc);
1213 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1214 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001215
Ray Milkey269ffb92014-04-03 14:43:30 -07001216 OFMatch matchBDDP = new OFMatch();
1217 matchBDDP.setDataLayerType((short) 0x8942);
1218 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1219 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001220
Ray Milkey269ffb92014-04-03 14:43:30 -07001221 OFActionOutput action = new OFActionOutput();
1222 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1223 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001224 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -07001225 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001226
Ray Milkey269ffb92014-04-03 14:43:30 -07001227 fmLLDP.setActions(actions);
1228 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001229
Ray Milkey269ffb92014-04-03 14:43:30 -07001230 fmLLDP.setPriority(ARP_PRIORITY);
1231 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1232 fmBDDP.setPriority(ARP_PRIORITY);
1233 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001234
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001235 List<OFFlowMod> flowModList = new ArrayList<>(3);
Ray Milkey269ffb92014-04-03 14:43:30 -07001236 flowModList.add(fm);
1237 flowModList.add(fmLLDP);
1238 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001239
Ray Milkey269ffb92014-04-03 14:43:30 -07001240 for (String strdpid : switches) {
1241 flowCache.write(HexString.toLong(strdpid), flowModList);
1242 }
Jonathan Hartc78b8f62014-08-07 22:31:09 -07001243 }*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001244
Ray Milkey269ffb92014-04-03 14:43:30 -07001245 private void beginRouting() {
1246 log.debug("Topology is now ready, beginning routing function");
1247 // TODO: Fix for the new Topology Network Graph
1248 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001249
Ray Milkey269ffb92014-04-03 14:43:30 -07001250 // Wait Pavlin's API. We need the following functions.
1251 /*setupArpFlows();
1252 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001253
Ray Milkey269ffb92014-04-03 14:43:30 -07001254 setupBgpPaths();
1255 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001256
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001257 // Suppress link discovery on external-facing router ports
Ray Milkey269ffb92014-04-03 14:43:30 -07001258 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -07001259 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001260 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001261
Ray Milkey269ffb92014-04-03 14:43:30 -07001262 bgpUpdatesExecutor.execute(new Runnable() {
1263 @Override
1264 public void run() {
1265 doUpdatesThread();
1266 }
1267 });
1268 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001269
Jonathan Hart938a0152014-04-07 18:27:31 -07001270 // Before inserting the paths for BGP traffic, we should check whether
1271 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001272 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001273 // TODO: Fix the code below after topoSwitchSerice was removed
1274 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001275 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001276
Ray Milkey269ffb92014-04-03 14:43:30 -07001277 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1278 getActiveSwitches().iterator();
1279 while(activeSwitches.hasNext())
1280 {
1281 ISwitchObject switchObject = activeSwitches.next();
1282 if (switchObject.getDPID().equals(dpid)) {
1283 break;
1284 }
1285 if(activeSwitches.hasNext() == false) {
1286 log.debug("Not all switches are here yet");
1287 return;
1288 }
1289 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001290 }
1291 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001292 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001293 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001294
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001295 // Actually we only need to go half way round to verify full mesh
1296 // connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001297 private void checkTopologyReady() {
1298 for (Interface dstInterface : interfaces.values()) {
1299 for (Interface srcInterface : interfaces.values()) {
1300 if (dstInterface.equals(srcInterface)) {
1301 continue;
1302 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001303
Ray Milkey269ffb92014-04-03 14:43:30 -07001304 // TODO: Fix for the new Topology Network Graph
1305 /*
1306 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1307 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001308
Ray Milkey269ffb92014-04-03 14:43:30 -07001309 if (shortestPath == null){
1310 log.debug("Shortest path between {} and {} not found",
1311 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1312 return;
1313 }
1314 */
1315 }
1316 }
1317 topologyReady = true;
1318 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001319
Ray Milkey269ffb92014-04-03 14:43:30 -07001320 private void checkStatus() {
1321 if (!switchesConnected) {
1322 checkSwitchesConnected();
1323 }
1324 boolean oldTopologyReadyStatus = topologyReady;
1325 if (switchesConnected && !topologyReady) {
1326 checkTopologyReady();
1327 }
1328 if (!oldTopologyReadyStatus && topologyReady) {
1329 beginRouting();
1330 }
1331 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001332
Ray Milkey269ffb92014-04-03 14:43:30 -07001333 private void doUpdatesThread() {
1334 boolean interrupted = false;
1335 try {
1336 while (true) {
1337 try {
1338 RibUpdate update = ribUpdates.take();
1339 switch (update.getOperation()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001340 case UPDATE:
1341 if (validateUpdate(update)) {
1342 processRibAdd(update);
1343 } else {
1344 log.debug("Rib UPDATE out of order: {} via {}",
1345 update.getPrefix(), update.getRibEntry().getNextHop());
1346 }
1347 break;
1348 case DELETE:
1349 if (validateUpdate(update)) {
1350 processRibDelete(update);
1351 } else {
1352 log.debug("Rib DELETE out of order: {} via {}",
1353 update.getPrefix(), update.getRibEntry().getNextHop());
1354 }
1355 break;
1356 default:
1357 log.error("Unknown operation {}", update.getOperation());
1358 break;
Ray Milkey269ffb92014-04-03 14:43:30 -07001359 }
1360 } catch (InterruptedException e) {
1361 log.debug("Interrupted while taking from updates queue", e);
1362 interrupted = true;
1363 } catch (Exception e) {
1364 log.debug("exception", e);
1365 }
1366 }
1367 } finally {
1368 if (interrupted) {
1369 Thread.currentThread().interrupt();
1370 }
1371 }
1372 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001373
Ray Milkey269ffb92014-04-03 14:43:30 -07001374 private boolean validateUpdate(RibUpdate update) {
1375 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001376 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
1377 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001378
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001379 // If there is no existing entry we must assume this is the most recent
1380 // update. However this might not always be the case as we might have a
1381 // POST then DELETE reordering.
1382 // if (oldEntry == null ||
1383 // !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001384 if (oldEntry == null) {
1385 return true;
1386 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001387
Ray Milkey269ffb92014-04-03 14:43:30 -07001388 // This handles the case where routes are gathered in the initial
1389 // request because they don't have sequence number info
1390 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1391 return true;
1392 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001393
Ray Milkey269ffb92014-04-03 14:43:30 -07001394 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1395 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001396 }
Ray Milkey4985f212014-04-10 16:57:05 -07001397
1398 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001399 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -07001400 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001401
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001402 private Interface longestInterfacePrefixMatch(InetAddress address) {
1403 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
1404 Prefix.MAX_PREFIX_LENGTH);
1405 Iterator<Interface> it =
1406 interfaceRoutes.getValuesForKeysPrefixing(
1407 prefixToSearchFor.toBinaryString()).iterator();
1408 Interface intf = null;
1409 // Find the last prefix, which will be the longest prefix
1410 while (it.hasNext()) {
1411 intf = it.next();
1412 }
1413
1414 return intf;
1415 }
1416
Ray Milkey269ffb92014-04-03 14:43:30 -07001417 // The code below should be reimplemented after removal of Floodlight's
1418 // ITopologyService API. It should be implemented on top of network graph
1419 // notifications. (It was pretty hacky anyway...)
1420 /*
1421 @Override
1422 public void topologyChanged() {
1423 if (topologyReady) {
1424 return;
1425 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001426
Ray Milkey269ffb92014-04-03 14:43:30 -07001427 boolean refreshNeeded = false;
1428 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1429 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1430 //We don't need to recalculate anything for just link updates
1431 //They happen very frequently
1432 refreshNeeded = true;
1433 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001434
Ray Milkey269ffb92014-04-03 14:43:30 -07001435 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001436
Ray Milkey269ffb92014-04-03 14:43:30 -07001437 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1438 synchronized (linkUpdates) {
1439 linkUpdates.add(ldu);
1440 }
1441 }
1442 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001443
Ray Milkey269ffb92014-04-03 14:43:30 -07001444 if (refreshNeeded && !topologyReady){
1445 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1446 }
1447 }
1448 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001449
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001450 // ******************
1451 // IOFSwitchListener
1452 // ******************
1453
Ray Milkey269ffb92014-04-03 14:43:30 -07001454 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001455 public void switchActivatedMaster(long swId) {
1456 IOFSwitch sw = floodlightProvider.getSwitch(swId);
1457 if (sw == null) {
1458 log.warn("Added switch not available {} ", swId);
1459 return;
1460 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001461 if (!topologyReady) {
1462 sw.clearAllFlowMods();
1463 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001464
Jonathan Hartc78b8f62014-08-07 22:31:09 -07001465 //flowCache.switchConnected(sw);
Ray Milkey269ffb92014-04-03 14:43:30 -07001466 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001467
Ray Milkey269ffb92014-04-03 14:43:30 -07001468 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001469 public void switchActivatedEqual(long swId) {
1470 // TODO Auto-generated method stub
1471
1472 }
1473
1474 @Override
1475 public void switchMasterToEqual(long swId) {
1476 // TODO Auto-generated method stub
1477
1478 }
1479
1480 @Override
1481 public void switchEqualToMaster(long swId) {
1482 // for now treat as switchActivatedMaster
1483 switchActivatedMaster(swId);
1484 }
1485
1486 @Override
1487 public void switchDisconnected(long swId) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001488 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001489 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001490
Ray Milkey269ffb92014-04-03 14:43:30 -07001491 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001492 public void switchPortChanged(long swId, OFPortDesc port, PortChangeType pct) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001493 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001494 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001495
Ray Milkey269ffb92014-04-03 14:43:30 -07001496 @Override
1497 public String getName() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001498 return "sdnip";
Ray Milkey269ffb92014-04-03 14:43:30 -07001499 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001500
Ray Milkey269ffb92014-04-03 14:43:30 -07001501 /*
1502 * IConfigInfoService methods
1503 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001504
Ray Milkey269ffb92014-04-03 14:43:30 -07001505 @Override
1506 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001507 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001508 return (intf != null && intf.getIpAddress().equals(address));
1509 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001510
Ray Milkey269ffb92014-04-03 14:43:30 -07001511 @Override
1512 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001513 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001514 return (intf != null && !intf.getIpAddress().equals(address));
1515 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001516
Ray Milkey269ffb92014-04-03 14:43:30 -07001517 @Override
1518 public boolean fromExternalNetwork(long inDpid, short inPort) {
1519 for (Interface intf : interfaces.values()) {
1520 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1521 return true;
1522 }
1523 }
1524 return false;
1525 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001526
Ray Milkey269ffb92014-04-03 14:43:30 -07001527 @Override
1528 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001529 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -07001530 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001531
Ray Milkey269ffb92014-04-03 14:43:30 -07001532 @Override
1533 public boolean hasLayer3Configuration() {
1534 return !interfaces.isEmpty();
1535 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001536
Ray Milkey269ffb92014-04-03 14:43:30 -07001537 @Override
1538 public MACAddress getRouterMacAddress() {
1539 return bgpdMacAddress;
1540 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001541
Ray Milkey269ffb92014-04-03 14:43:30 -07001542 @Override
1543 public short getVlan() {
1544 return vlan;
1545 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001546}