blob: 4e4e6fa1e30d04bb07bde34000dc2f08cb8e5912 [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 Harte7e1c6e2013-06-04 20:50:23 -07009import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070010import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120011import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120012import java.util.concurrent.BlockingQueue;
13import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120014import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120015import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120016import java.util.concurrent.ScheduledExecutorService;
17import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080018
Jonathan Hart61ba9372013-05-19 20:10:29 -070019import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070020import net.floodlightcontroller.core.IOFSwitch;
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;
Jonathan Hart98957bf2013-07-01 14:49:24 +120026import net.floodlightcontroller.core.util.SingletonTask;
pingping-lina2cbfad2013-03-07 08:39:21 +080027import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120028import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0961fe82014-04-03 09:56:25 -070029import net.onrc.onos.apps.proxyarp.IArpRequester;
30import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart8f6dc092014-04-18 15:56:43 -070031import net.onrc.onos.apps.sdnip.RibUpdate.Operation;
32import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutable;
Jonathan Hart23701d12014-04-03 10:45:48 -070033import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harta99ec672014-04-03 11:30:34 -070034import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070035import net.onrc.onos.core.main.config.IConfigInfoService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070036import net.onrc.onos.core.packet.Ethernet;
37import net.onrc.onos.core.packet.IPv4;
Jonathan Hart23701d12014-04-03 10:45:48 -070038import net.onrc.onos.core.util.CallerId;
39import net.onrc.onos.core.util.DataPath;
40import net.onrc.onos.core.util.Dpid;
41import net.onrc.onos.core.util.FlowEntryAction;
42import net.onrc.onos.core.util.FlowEntryActions;
43import net.onrc.onos.core.util.FlowEntryMatch;
44import net.onrc.onos.core.util.FlowId;
45import net.onrc.onos.core.util.FlowPath;
46import net.onrc.onos.core.util.FlowPathFlags;
47import net.onrc.onos.core.util.FlowPathType;
48import net.onrc.onos.core.util.FlowPathUserState;
49import net.onrc.onos.core.util.IPv4Net;
50import net.onrc.onos.core.util.Port;
51import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080052import net.sf.json.JSONArray;
53import net.sf.json.JSONObject;
54import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080055
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070056import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120057import org.codehaus.jackson.JsonParseException;
58import org.codehaus.jackson.map.JsonMappingException;
59import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070060import org.openflow.protocol.OFFlowMod;
61import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070062import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120063import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070064import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070065import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120066import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080067import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
69
Jonathan Hart4dfc3652013-08-02 20:22:36 +120070import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120071import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120072import com.google.common.collect.Multimaps;
73import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120074import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120075import com.google.common.util.concurrent.ThreadFactoryBuilder;
76
Jonathan Hart8f6dc092014-04-18 15:56:43 -070077public class SdnIp implements IFloodlightModule, ISdnIpService,
Ray Milkey269ffb92014-04-03 14:43:30 -070078 IArpRequester,
79 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070080
Jonathan Hart8f6dc092014-04-18 15:56:43 -070081 private static final Logger log = LoggerFactory.getLogger(SdnIp.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080082
Ray Milkey269ffb92014-04-03 14:43:30 -070083 private IFloodlightProviderService floodlightProvider;
84 private ILinkDiscoveryService linkDiscoveryService;
85 private IRestApiService restApi;
86 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070087
Jonathan Hart5e54f2e2014-04-17 13:43:40 -070088 private IPatriciaTree<RibEntry> ptree;
89 private IPatriciaTree<Interface> interfacePtree;
Ray Milkey269ffb92014-04-03 14:43:30 -070090 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070091
Ray Milkey269ffb92014-04-03 14:43:30 -070092 private String bgpdRestIp;
93 private String routerId;
Ray Milkey5df613b2014-04-15 10:50:56 -070094 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
95 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070096
Ray Milkey2476cac2014-04-08 11:03:21 -070097 private static final short ARP_PRIORITY = 20;
Ray Milkey5d406012014-04-08 14:44:41 -070098
Jonathan Hart938a0152014-04-07 18:27:31 -070099 // The fields below are unused after the move to FlowManager.
100 // Remove them if no longer needed.
101 /*
102 // We need to identify our flows somehow, in lieu of an OS-wide mechanism
103 // to hand out cookie IDs to prevent conflicts.
104 private static final long APP_COOKIE = 0xa0000000000000L;
105 // Cookie for flows that do L2 forwarding within SDN domain to egress routers
106 private static final long L2_FWD_COOKIE = APP_COOKIE + 1;
107 // Cookie for flows in ingress switches that rewrite the MAC address
108 private static final long MAC_RW_COOKIE = APP_COOKIE + 2;
109 // Cookie for flows that setup BGP paths
110 private static final long BGP_COOKIE = APP_COOKIE + 3;
111 // Forwarding uses priority 0, and the mac rewrite entries in ingress switches
112 // need to be higher priority than this otherwise the rewrite may not get done
113 private static final short SDNIP_PRIORITY = 10;
114 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700115
Ray Milkey2476cac2014-04-08 11:03:21 -0700116 private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700117
Jonathan Hart938a0152014-04-07 18:27:31 -0700118 private static final int TOPO_DETECTION_WAIT = 2; // seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700119
Jonathan Hart938a0152014-04-07 18:27:31 -0700120 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700121 private List<String> switches;
122 private Map<String, Interface> interfaces;
123 private Map<InetAddress, BgpPeer> bgpPeers;
124 private SwitchPort bgpdAttachmentPoint;
125 private MACAddress bgpdMacAddress;
126 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700127
Jonathan Hart938a0152014-04-07 18:27:31 -0700128 // True when all switches have connected
Ray Milkey269ffb92014-04-03 14:43:30 -0700129 private volatile boolean switchesConnected = false;
Jonathan Hart938a0152014-04-07 18:27:31 -0700130 // True when we have a full mesh of shortest paths between gateways
Ray Milkey269ffb92014-04-03 14:43:30 -0700131 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200132
Jonathan Hart938a0152014-04-07 18:27:31 -0700133 private List<LDUpdate> linkUpdates;
Ray Milkey269ffb92014-04-03 14:43:30 -0700134 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700135
Ray Milkey269ffb92014-04-03 14:43:30 -0700136 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700137
Ray Milkey269ffb92014-04-03 14:43:30 -0700138 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700139
Ray Milkey269ffb92014-04-03 14:43:30 -0700140 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700141
Ray Milkey269ffb92014-04-03 14:43:30 -0700142 private Map<InetAddress, Path> pushedPaths;
143 private Map<Prefix, Path> prefixToPath;
144 // private Multimap<Prefix, PushedFlowMod> pushedFlows;
145 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700146
Ray Milkey269ffb92014-04-03 14:43:30 -0700147 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700148
Ray Milkey269ffb92014-04-03 14:43:30 -0700149 // TODO: Fix for the new Topology Network Graph
150 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700151
Ray Milkey269ffb92014-04-03 14:43:30 -0700152 private class TopologyChangeDetector implements Runnable {
153 @Override
154 public void run() {
155 log.debug("Running topology change detection task");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700156 // TODO: Fix the code below after topoLinkService was removed
157 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700158 synchronized (linkUpdates) {
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700159
Ray Milkey269ffb92014-04-03 14:43:30 -0700160 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700161
Ray Milkey269ffb92014-04-03 14:43:30 -0700162 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700163
Ray Milkey269ffb92014-04-03 14:43:30 -0700164 Iterator<LDUpdate> it = linkUpdates.iterator();
165 while (it.hasNext()){
166 LDUpdate ldu = it.next();
167 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
168 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700169
Ray Milkey269ffb92014-04-03 14:43:30 -0700170 if (activeLinks.contains(l)){
171 it.remove();
172 }
173 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 }
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700175 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700176
Ray Milkey269ffb92014-04-03 14:43:30 -0700177 if (!topologyReady) {
178 if (linkUpdates.isEmpty()) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700179 // All updates have been seen in network map.
180 // We can check if topology is ready
Ray Milkey269ffb92014-04-03 14:43:30 -0700181 log.debug("No known changes outstanding. Checking topology now");
182 checkStatus();
183 } else {
Jonathan Hart938a0152014-04-07 18:27:31 -0700184 // We know of some link updates that haven't propagated to the database yet
Ray Milkey269ffb92014-04-03 14:43:30 -0700185 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
186 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
187 }
188 }
189 }
190 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700191
Ray Milkey269ffb92014-04-03 14:43:30 -0700192 private void readConfiguration(String configFilename) {
193 File gatewaysFile = new File(configFilename);
194 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700195
Ray Milkey269ffb92014-04-03 14:43:30 -0700196 try {
197 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700198
Ray Milkey269ffb92014-04-03 14:43:30 -0700199 switches = config.getSwitches();
200 interfaces = new HashMap<String, Interface>();
201 for (Interface intf : config.getInterfaces()) {
202 interfaces.put(intf.getName(), intf);
203 }
204 bgpPeers = new HashMap<InetAddress, BgpPeer>();
205 for (BgpPeer peer : config.getPeers()) {
206 bgpPeers.put(peer.getIpAddress(), peer);
207 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700208
Ray Milkey269ffb92014-04-03 14:43:30 -0700209 bgpdAttachmentPoint = new SwitchPort(
210 new Dpid(config.getBgpdAttachmentDpid()),
211 new Port(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700212
Ray Milkey269ffb92014-04-03 14:43:30 -0700213 bgpdMacAddress = config.getBgpdMacAddress();
214 vlan = config.getVlan();
215 } catch (JsonParseException e) {
216 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700217 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700218 } catch (JsonMappingException e) {
219 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700220 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700221 } catch (IOException e) {
222 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700223 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700224 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700225
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700226 // Populate the interface Patricia Tree
Ray Milkey269ffb92014-04-03 14:43:30 -0700227 for (Interface intf : interfaces.values()) {
228 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700229 interfacePtree.put(prefix, intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700230 }
231 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700232
Ray Milkey269ffb92014-04-03 14:43:30 -0700233 @Override
234 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
235 Collection<Class<? extends IFloodlightService>> l
236 = new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700237 l.add(ISdnIpService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700238 l.add(IConfigInfoService.class);
239 return l;
240 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700241
Ray Milkey269ffb92014-04-03 14:43:30 -0700242 @Override
243 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
244 Map<Class<? extends IFloodlightService>, IFloodlightService> m
245 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700246 m.put(ISdnIpService.class, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700247 m.put(IConfigInfoService.class, this);
248 return m;
249 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800250
Ray Milkey269ffb92014-04-03 14:43:30 -0700251 @Override
252 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
253 Collection<Class<? extends IFloodlightService>> l
254 = new ArrayList<Class<? extends IFloodlightService>>();
255 l.add(IFloodlightProviderService.class);
256 l.add(IRestApiService.class);
257 return l;
258 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700259
Ray Milkey269ffb92014-04-03 14:43:30 -0700260 @Override
261 public void init(FloodlightModuleContext context)
262 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700263
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700264 ptree = new PatriciaTree<RibEntry>(32);
265 interfacePtree = new PatriciaTree<Interface>(32);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700266
Ray Milkey269ffb92014-04-03 14:43:30 -0700267 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700268
Ray Milkey269ffb92014-04-03 14:43:30 -0700269 // Register floodlight provider and REST handler.
270 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
271 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
272 restApi = context.getServiceImpl(IRestApiService.class);
273 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800274
Ray Milkey269ffb92014-04-03 14:43:30 -0700275 linkUpdates = new ArrayList<LDUpdate>();
276 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
277 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700278
Ray Milkey269ffb92014-04-03 14:43:30 -0700279 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
280 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
281 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700282
Ray Milkey269ffb92014-04-03 14:43:30 -0700283 pushedPaths = new HashMap<InetAddress, Path>();
284 prefixToPath = new HashMap<Prefix, Path>();
285// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
286 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700287
Ray Milkey269ffb92014-04-03 14:43:30 -0700288 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700289
Ray Milkey269ffb92014-04-03 14:43:30 -0700290 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
291 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700292
Jonathan Hart938a0152014-04-07 18:27:31 -0700293 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700294 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
295 if (bgpdRestIp == null) {
296 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700297 throw new ConfigurationRuntimeException(
298 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700299 } else {
300 log.info("BgpdRestIp set to {}", bgpdRestIp);
301 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700302
Ray Milkey269ffb92014-04-03 14:43:30 -0700303 routerId = context.getConfigParams(this).get("RouterId");
304 if (routerId == null) {
305 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700306 throw new ConfigurationRuntimeException(
307 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700308 } else {
309 log.info("RouterId set to {}", routerId);
310 }
pingping-linba5c52f2014-02-11 16:52:01 -0800311
Ray Milkey269ffb92014-04-03 14:43:30 -0700312 String configFilenameParameter = context.getConfigParams(this).get("configfile");
313 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700314 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700315 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700316 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700317
Ray Milkey5df613b2014-04-15 10:50:56 -0700318 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700319 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700320
Ray Milkey269ffb92014-04-03 14:43:30 -0700321 @Override
322 public void startUp(FloodlightModuleContext context) {
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700323 restApi.addRestletRoutable(new SdnIpWebRoutable());
Ray Milkey269ffb92014-04-03 14:43:30 -0700324 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800325
Jonathan Hart938a0152014-04-07 18:27:31 -0700326 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700327 retrieveRib();
328 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800329
Ray Milkey269ffb92014-04-03 14:43:30 -0700330 @Override
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700331 public IPatriciaTree<RibEntry> getPtree() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700332 return ptree;
333 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700334
Ray Milkey269ffb92014-04-03 14:43:30 -0700335 @Override
336 public void clearPtree() {
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700337 ptree = new PatriciaTree<RibEntry>(32);
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
Jonathan Hart31e15f12014-04-10 10:33:00 -0700341 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700342 return bgpdRestIp;
343 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700344
Ray Milkey269ffb92014-04-03 14:43:30 -0700345 @Override
346 public String getRouterId() {
347 return routerId;
348 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700349
Ray Milkey269ffb92014-04-03 14:43:30 -0700350 private void retrieveRib() {
351 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
352 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700353
Jonathan Hart938a0152014-04-07 18:27:31 -0700354 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700355 return;
356 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700357
Ray Milkey269ffb92014-04-03 14:43:30 -0700358 response = response.replaceAll("\"", "'");
359 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
Jonathan Hart938a0152014-04-07 18:27:31 -0700360 JSONArray ribArray = jsonObj.getJSONArray("rib");
Ray Milkey5df613b2014-04-15 10:50:56 -0700361 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700362
Jonathan Hart938a0152014-04-07 18:27:31 -0700363 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700364
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700366
Ray Milkey269ffb92014-04-03 14:43:30 -0700367 for (int j = 0; j < size; j++) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700368 JSONObject ribEntry = ribArray.getJSONObject(j);
369 String prefix = ribEntry.getString("prefix");
370 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700371
Jonathan Hart938a0152014-04-07 18:27:31 -0700372 // Insert each rib entry into the local rib
Ray Milkey269ffb92014-04-03 14:43:30 -0700373 String[] substring = prefix.split("/");
374 String prefix1 = substring[0];
375 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700376
Ray Milkey269ffb92014-04-03 14:43:30 -0700377 Prefix p;
378 try {
379 p = new Prefix(prefix1, Integer.valueOf(mask1));
380 } catch (NumberFormatException e) {
381 log.warn("Wrong mask format in RIB JSON: {}", mask1);
382 continue;
383 } catch (IllegalArgumentException e1) {
384 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
385 continue;
386 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700387
Ray Milkey5df613b2014-04-15 10:50:56 -0700388 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700389
Ray Milkey269ffb92014-04-03 14:43:30 -0700390 try {
391 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
392 } catch (InterruptedException e) {
393 log.debug("Interrupted while pushing onto update queue");
394 }
395 }
396 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700397
Ray Milkey269ffb92014-04-03 14:43:30 -0700398 @Override
399 public void newRibUpdate(RibUpdate update) {
400 try {
401 ribUpdates.put(update);
402 } catch (InterruptedException e) {
403 log.debug("Interrupted while putting on ribUpdates queue", e);
404 Thread.currentThread().interrupt();
405 }
406 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700407
Jonathan Hart938a0152014-04-07 18:27:31 -0700408 public void processRibAdd(RibUpdate update) {
409 synchronized (this) {
410 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700411
Jonathan Hart938a0152014-04-07 18:27:31 -0700412 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700413
Jonathan Hart938a0152014-04-07 18:27:31 -0700414 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700415
Jonathan Hart938a0152014-04-07 18:27:31 -0700416 if (rib != null && !rib.equals(update.getRibEntry())) {
417 // There was an existing nexthop for this prefix. This update supersedes that,
418 // so we need to remove the old flows for this prefix from the switches
Ray Milkey7531a342014-04-11 15:08:12 -0700419 executeDeletePrefix(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700420 }
Ray Milkey5d406012014-04-08 14:44:41 -0700421
Jonathan Hart938a0152014-04-07 18:27:31 -0700422 if (update.getRibEntry().getNextHop().equals(
423 InetAddresses.forString("0.0.0.0"))) {
424 // Route originated by SDN domain
425 // We don't handle these at the moment
426 log.debug("Own route {} to {}", prefix,
427 update.getRibEntry().getNextHop().getHostAddress());
428 return;
429 }
Ray Milkey5d406012014-04-08 14:44:41 -0700430
Ray Milkey7531a342014-04-11 15:08:12 -0700431 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700432 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700433 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700434
Ray Milkey7531a342014-04-11 15:08:12 -0700435 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700436 // TODO: Fix the code below. Note that "deviceStorage" was removed.
437
438 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700439 Prefix prefix = update.getPrefix();
440 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700441
Ray Milkey269ffb92014-04-03 14:43:30 -0700442 InetAddress dstIpAddress = rib.getNextHop();
443 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800444
Ray Milkey269ffb92014-04-03 14:43:30 -0700445 // See if we know the MAC address of the next hop
446 // 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 -0700447 IDeviceObject nextHopDevice =
448 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700449
Ray Milkey269ffb92014-04-03 14:43:30 -0700450 if (nextHopDevice == null){
451 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
452 prefixesWaitingOnArp.put(dstIpAddress,
453 new RibUpdate(Operation.UPDATE, prefix, rib));
454 proxyArp.sendArpRequest(dstIpAddress, this, true);
455 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800456
Ray Milkey269ffb92014-04-03 14:43:30 -0700457 }
458 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700459
Ray Milkey269ffb92014-04-03 14:43:30 -0700460 // Find the attachment point (egress interface) of the next hop
461 Interface egressInterface = null;
462 if (bgpPeers.containsKey(dstIpAddress)) {
463 //Route to a peer
464 log.debug("Route to peer {}", dstIpAddress);
465 BgpPeer peer = bgpPeers.get(dstIpAddress);
466 egressInterface = interfaces.get(peer.getInterfaceName());
467 } else {
468 //Route to non-peer
469 log.debug("Route to non-peer {}", dstIpAddress);
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700470 egressInterface = interfacePtree.match(
Ray Milkey269ffb92014-04-03 14:43:30 -0700471 new Prefix(dstIpAddress.getAddress(), 32));
472 if (egressInterface == null) {
473 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
474 return;
475 }
476 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700477
Ray Milkey269ffb92014-04-03 14:43:30 -0700478 if (nextHopMacAddress == null) {
479 prefixesWaitingOnArp.put(dstIpAddress,
480 new RibUpdate(Operation.UPDATE, prefix, rib));
481 proxyArp.sendArpRequest(dstIpAddress, this, true);
482 return;
483 } else {
484 if (!bgpPeers.containsKey(dstIpAddress)) {
485 //If the prefix is for a non-peer we need to ensure there's a path,
486 //and push one if there isn't.
487 Path path = pushedPaths.get(dstIpAddress);
488 if (path == null) {
489 path = new Path(egressInterface, dstIpAddress);
490 calculateAndPushPath(path, nextHopMacAddress);
491 pushedPaths.put(dstIpAddress, path);
492 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700493
Ray Milkey269ffb92014-04-03 14:43:30 -0700494 path.incrementUsers();
495 prefixToPath.put(prefix, path);
496 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700497
Ray Milkey269ffb92014-04-03 14:43:30 -0700498 //For all prefixes we need to add the first-hop mac-rewriting flows
499 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
500 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700501 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700502 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700503
Ray Milkey269ffb92014-04-03 14:43:30 -0700504 /**
505 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
Ray Milkeyb41100a2014-04-10 10:42:15 -0700506 * to all other border switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700507 */
508 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
509 MACAddress nextHopMacAddress) {
510 log.debug("Adding flows for prefix {}, next hop mac {}",
511 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700512
Ray Milkey269ffb92014-04-03 14:43:30 -0700513 FlowPath flowPath = new FlowPath();
514 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700515
Ray Milkey269ffb92014-04-03 14:43:30 -0700516 // Set flowPath FlowPathType and FlowPathUserState
517 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
518 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800519
Ray Milkey269ffb92014-04-03 14:43:30 -0700520 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
521 // only to the first-host switches
522 FlowPathFlags flowPathFlags = new FlowPathFlags();
523 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
524 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800525
Ray Milkey269ffb92014-04-03 14:43:30 -0700526 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700527 SwitchPort dstPort =
528 new SwitchPort(new Dpid(egressInterface.getDpid()),
529 new Port(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800530
Ray Milkey269ffb92014-04-03 14:43:30 -0700531 // We only need one flow mod per switch, so pick one interface on each switch
532 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
533 for (Interface intf : interfaces.values()) {
534 if (!srcInterfaces.containsKey(intf.getDpid())
535 && !intf.equals(egressInterface)) {
536 srcInterfaces.put(intf.getDpid(), intf);
537 }
538 }
539 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800540
Ray Milkey269ffb92014-04-03 14:43:30 -0700541 if (egressInterface.equals(srcInterface)) {
542 continue;
543 }
pingping-linba5c52f2014-02-11 16:52:01 -0800544
Ray Milkey269ffb92014-04-03 14:43:30 -0700545 // Create flowPath FlowId
546 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800547
Ray Milkey269ffb92014-04-03 14:43:30 -0700548 // Create DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700549 SwitchPort srcPort =
550 new SwitchPort(new Dpid(srcInterface.getDpid()),
551 new Port(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800552
Ray Milkey269ffb92014-04-03 14:43:30 -0700553 DataPath dataPath = new DataPath();
554 dataPath.setSrcPort(srcPort);
555 dataPath.setDstPort(dstPort);
556 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800557
Ray Milkey269ffb92014-04-03 14:43:30 -0700558 // Create flow path matching condition(s): IPv4 Prefix
559 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700560 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700561 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
562 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
563 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300564
Ray Milkey269ffb92014-04-03 14:43:30 -0700565 /*
566 * Create the Flow Entry Action(s): dst-MAC rewrite action
567 */
568 FlowEntryActions flowEntryActions = new FlowEntryActions();
569 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
570 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
571 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
572 flowEntryActions.addAction(flowEntryAction1);
573 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800574
Ray Milkey269ffb92014-04-03 14:43:30 -0700575 // Flow Path installation, only to first hop switches
576 // TODO: Add the flow by using the new Path Intent framework
577 /*
578 if (flowManagerService.addFlow(flowPath) == null) {
579 log.error("Failed to install flow path to the first hop for " +
580 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
581 nextHopMacAddress);
582 }
583 else {
584 log.debug("Successfully installed flow path to the first hop " +
585 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
586 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800587
Ray Milkey269ffb92014-04-03 14:43:30 -0700588 pushedFlowIds.put(prefix, flowPath.flowId());
589 }
590 */
591 }
592 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700593
Jonathan Hart938a0152014-04-07 18:27:31 -0700594 public void processRibDelete(RibUpdate update) {
595 synchronized (this) {
596 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700597
Jonathan Hart938a0152014-04-07 18:27:31 -0700598 if (ptree.remove(prefix, update.getRibEntry())) {
599 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700600 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700601 * If no entry was removed, the <prefix, nexthop> wasn't there so
602 * it's probably already been removed and we don't need to do anything
603 */
Ray Milkey7531a342014-04-11 15:08:12 -0700604 executeDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart938a0152014-04-07 18:27:31 -0700605 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700606 }
607 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700608
Ray Milkey7531a342014-04-11 15:08:12 -0700609 private void executeDeletePrefix(Prefix prefix, RibEntry ribEntry) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700610 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700611
Ray Milkey269ffb92014-04-03 14:43:30 -0700612 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700613
Ray Milkey269ffb92014-04-03 14:43:30 -0700614 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
615 log.debug("Getting path for route with non-peer nexthop");
616 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700617
Ray Milkey269ffb92014-04-03 14:43:30 -0700618 if (path != null) {
619 //path could be null if we added to the Ptree but didn't push
620 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700621
Ray Milkey269ffb92014-04-03 14:43:30 -0700622 path.decrementUsers();
623 if (path.getUsers() <= 0 && !path.isPermanent()) {
624 deletePath(path);
625 pushedPaths.remove(path.getDstIpAddress());
626 }
627 }
628 }
629 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700630
Ray Milkey269ffb92014-04-03 14:43:30 -0700631 // TODO have not tested this module
632 private void deletePrefixFlows(Prefix prefix) {
633 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700634
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700635 //
636 // TODO: Delete the flow by using the new Path Intent framework
637 // NOTE: During the refactoring of the code below, if obtaining
638 // the values of the removed flowIds is needed, the first
639 // removeAll() statement should be replaced with the second removeAll()
640 // statement.
641 //
642 pushedFlowIds.removeAll(prefix);
643 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700644 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
645 for (FlowId flowId : flowIds) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700646 if (log.isTraceEnabled()) {
647 //Trace the flow status by flowPath in the switch before deleting it
648 log.trace("Pushing a DELETE flow mod to flowPath : {}",
649 flowManagerService.getFlow(flowId).toString());
650 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700651
Ray Milkey269ffb92014-04-03 14:43:30 -0700652 if( flowManagerService.deleteFlow(flowId))
653 {
654 log.debug("Successfully deleted FlowId: {}",flowId);
655 }
656 else
657 {
658 log.debug("Failed to delete FlowId: {}",flowId);
659 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700660 }
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700661 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700662 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700663
Ray Milkey269ffb92014-04-03 14:43:30 -0700664 // TODO need to record the path and then delete here
665 private void deletePath(Path path) {
666 log.debug("Deleting flows for path to {}",
667 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700668
Ray Milkey269ffb92014-04-03 14:43:30 -0700669 // TODO need update
670 /*for (PushedFlowMod pfm : path.getFlowMods()) {
671 if (log.isTraceEnabled()) {
672 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
673 new Object[] {HexString.toHexString(pfm.getDpid()),
674 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
675 });
676 }
pingping-linba5c52f2014-02-11 16:52:01 -0800677
Ray Milkey269ffb92014-04-03 14:43:30 -0700678 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
679 }*/
680 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700681
682
Ray Milkey269ffb92014-04-03 14:43:30 -0700683 //TODO test next-hop changes
684 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800685
Ray Milkey269ffb92014-04-03 14:43:30 -0700686 /**
687 * On startup, we need to calculate a full mesh of paths between all gateway
Ray Milkeyb41100a2014-04-10 10:42:15 -0700688 * switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700689 */
690 private void setupFullMesh() {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700691 // TODO: Fix the code below. Note that "deviceStorage" was removed.
692
693 /*
694
Ray Milkey269ffb92014-04-03 14:43:30 -0700695 //For each border router, calculate and install a path from every other
696 //border switch to said border router. However, don't install the entry
697 //in to the first hop switch, as we need to install an entry to rewrite
698 //for each prefix received. This will be done later when prefixes have
699 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700700
Ray Milkey269ffb92014-04-03 14:43:30 -0700701 for (BgpPeer peer : bgpPeers.values()) {
702 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700703
Ray Milkey269ffb92014-04-03 14:43:30 -0700704 //We know there's not already a Path here pushed, because this is
705 //called before all other routing
706 Path path = new Path(peerInterface, peer.getIpAddress());
707 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700708
Ray Milkey269ffb92014-04-03 14:43:30 -0700709 //See if we know the MAC address of the peer. If not we can't
710 //do anything until we learn it
Ray Milkey269ffb92014-04-03 14:43:30 -0700711 MACAddress macAddress = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700712 IDeviceObject nextHopDevice =
713 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800714
Ray Milkey269ffb92014-04-03 14:43:30 -0700715 if(nextHopDevice == null){
716 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
717 //Put in the pending paths list first
718 pathsWaitingOnArp.put(peer.getIpAddress(), path);
719 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
720 continue;
721 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700722
Ray Milkey269ffb92014-04-03 14:43:30 -0700723 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
pingping-linba5c52f2014-02-11 16:52:01 -0800724
Ray Milkey269ffb92014-04-03 14:43:30 -0700725 if (macAddress == null) {
726 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
727 //Put in the pending paths list first
728 pathsWaitingOnArp.put(peer.getIpAddress(), path);
729 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
730 continue;
731 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700732
Ray Milkey269ffb92014-04-03 14:43:30 -0700733 //If we know the MAC, lets go ahead and push the paths to this peer
734 calculateAndPushPath(path, macAddress);
735 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700736 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700737 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700738
Ray Milkey269ffb92014-04-03 14:43:30 -0700739 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
740 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700741
Ray Milkey269ffb92014-04-03 14:43:30 -0700742 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
743 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800744
Ray Milkey269ffb92014-04-03 14:43:30 -0700745 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800746
Ray Milkey269ffb92014-04-03 14:43:30 -0700747 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800748
Ray Milkey269ffb92014-04-03 14:43:30 -0700749 // Set flowPath FlowPathType and FlowPathUserState
750 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
751 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800752
Ray Milkey269ffb92014-04-03 14:43:30 -0700753 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
754 FlowPathFlags flowPathFlags = new FlowPathFlags();
755 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
756 flowPath.setFlowPathFlags(flowPathFlags);
757
758 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700759 SwitchPort dstPort =
760 new SwitchPort(new Dpid(dstInterface.getDpid()),
761 new Port(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800762
Ray Milkey269ffb92014-04-03 14:43:30 -0700763 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800764
Ray Milkey269ffb92014-04-03 14:43:30 -0700765 if (dstInterface.equals(srcInterface)) {
766 continue;
767 }
pingping-linba5c52f2014-02-11 16:52:01 -0800768
Ray Milkey269ffb92014-04-03 14:43:30 -0700769 // Create flowPath FlowId
770 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800771
Ray Milkey269ffb92014-04-03 14:43:30 -0700772 // Create the DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700773 SwitchPort srcPort =
774 new SwitchPort(new Dpid(srcInterface.getDpid()),
775 new Port(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800776
Ray Milkey269ffb92014-04-03 14:43:30 -0700777 DataPath dataPath = new DataPath();
778 dataPath.setSrcPort(srcPort);
779 dataPath.setDstPort(dstPort);
780 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800781
Ray Milkey269ffb92014-04-03 14:43:30 -0700782 // Create the Flow Path Match condition(s)
783 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700784 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700785 flowEntryMatch.enableDstMac(dstMacAddress);
786 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800787
Ray Milkey269ffb92014-04-03 14:43:30 -0700788 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
789 // Shortest Path Flow, and is always the last action for the Flow Entries
790 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
791 // TODO: Add the flow by using the new Path Intent framework
792 /*
793 if (flowManagerService.addFlow(flowPath) == null) {
794 log.error("Failed to set up MAC based forwarding path to {}, {}",
795 path.getDstIpAddress().getHostAddress(),dstMacAddress);
796 }
797 else {
798 log.debug("Successfully set up MAC based forwarding path to {}, {}",
799 path.getDstIpAddress().getHostAddress(),dstMacAddress);
800 }
801 */
802 }
803 }
pingping-linba5c52f2014-02-11 16:52:01 -0800804
Ray Milkey269ffb92014-04-03 14:43:30 -0700805 /**
Jonathan Hart938a0152014-04-07 18:27:31 -0700806 * Proactively install all BGP traffic paths from BGP host attachment point
Ray Milkeyb41100a2014-04-10 10:42:15 -0700807 * in SDN network to all the virtual gateways to BGP peers in other networks.
Ray Milkey269ffb92014-04-03 14:43:30 -0700808 */
809 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200810
Ray Milkey269ffb92014-04-03 14:43:30 -0700811 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800812
Ray Milkey269ffb92014-04-03 14:43:30 -0700813 FlowPath flowPath = new FlowPath();
814 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800815
Ray Milkey269ffb92014-04-03 14:43:30 -0700816 // Set flowPath FlowPathType and FlowPathUserState
817 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
818 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800819
Ray Milkey269ffb92014-04-03 14:43:30 -0700820 // Install flow paths between BGPd and its peers
821 // There is no need to set the FlowPathFlags
822 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800823
Ray Milkey269ffb92014-04-03 14:43:30 -0700824 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
pingping-linba5c52f2014-02-11 16:52:01 -0800825
Ray Milkey269ffb92014-04-03 14:43:30 -0700826 // Create the Flow Path Match condition(s)
827 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700828 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
pingping-linba5c52f2014-02-11 16:52:01 -0800829
Ray Milkey269ffb92014-04-03 14:43:30 -0700830 // Match both source address and dest address
831 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress() + "/32");
832 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800833
Ray Milkey269ffb92014-04-03 14:43:30 -0700834 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress().getHostAddress() + "/32");
835 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800836
Ray Milkey269ffb92014-04-03 14:43:30 -0700837 // Match TCP protocol
838 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800839
Ray Milkey269ffb92014-04-03 14:43:30 -0700840 // Match destination TCP port
841 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
842 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800843
Ray Milkey269ffb92014-04-03 14:43:30 -0700844 /**
845 * Create the DataPath: BGP -> BGP peer
846 */
847 // Flow path for src-TCP-port
848 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800849
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700850 SwitchPort srcPort =
851 new SwitchPort(bgpdAttachmentPoint.dpid(),
852 bgpdAttachmentPoint.port());
Ray Milkey269ffb92014-04-03 14:43:30 -0700853 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800854
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700855 SwitchPort dstPort =
856 new SwitchPort(new Dpid(peerInterface.getDpid()),
857 new Port(peerInterface.getSwitchPort().port()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700858 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800859
Ray Milkey269ffb92014-04-03 14:43:30 -0700860 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800861
Ray Milkey269ffb92014-04-03 14:43:30 -0700862 // TODO: Add the flow by using the new Path Intent framework
863 /*
864 if (flowManagerService.addFlow(flowPath) == null) {
865 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
866 bgpPeer.getIpAddress().getHostAddress());
867 }
868 else {
869 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
870 bgpPeer.getIpAddress().getHostAddress());
871 }
872 */
pingping-linba5c52f2014-02-11 16:52:01 -0800873
Ray Milkey269ffb92014-04-03 14:43:30 -0700874 // Disable dst-TCP-port, and set src-TCP-port
875 flowEntryMatch.disableDstTcpUdpPort();
876 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
877 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800878
Ray Milkey269ffb92014-04-03 14:43:30 -0700879 // Create a new FlowId
880 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800881
Ray Milkey269ffb92014-04-03 14:43:30 -0700882 // TODO: Add the flow by using the new Path Intent framework
883 /*
884 if (flowManagerService.addFlow(flowPath) == null) {
885 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
886 bgpPeer.getIpAddress().getHostAddress());
887 }
888 else {
889 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
890 bgpPeer.getIpAddress().getHostAddress());
891 }
892 */
pingping-linba5c52f2014-02-11 16:52:01 -0800893
Ray Milkey269ffb92014-04-03 14:43:30 -0700894 /**
895 * Create the DataPath: BGP <-BGP peer
896 */
897 // Reversed BGP flow path for src-TCP-port
898 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800899
Ray Milkey2476cac2014-04-08 11:03:21 -0700900 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800901
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700902 SwitchPort reverseDstPort =
903 new SwitchPort(bgpdAttachmentPoint.dpid(),
904 bgpdAttachmentPoint.port());
Ray Milkey2476cac2014-04-08 11:03:21 -0700905 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800906
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700907 SwitchPort reverseSrcPort =
908 new SwitchPort(new Dpid(peerInterface.getDpid()),
909 new Port(peerInterface.getSwitchPort().port()));
Ray Milkey2476cac2014-04-08 11:03:21 -0700910 reverseDataPath.setSrcPort(reverseSrcPort);
911 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800912
Jonathan Hart938a0152014-04-07 18:27:31 -0700913 // Reverse the dst IP and src IP addresses
Ray Milkey269ffb92014-04-03 14:43:30 -0700914 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
915 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
916 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800917
Ray Milkey269ffb92014-04-03 14:43:30 -0700918 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800919
Ray Milkey269ffb92014-04-03 14:43:30 -0700920 // TODO: Add the flow by using the new Path Intent framework
921 /*
922 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800923
Ray Milkey269ffb92014-04-03 14:43:30 -0700924 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
925 bgpPeer.getIpAddress().getHostAddress());
926 }
927 else {
928 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
929 bgpPeer.getIpAddress().getHostAddress());
930 }
931 */
pingping-linba5c52f2014-02-11 16:52:01 -0800932
Ray Milkey269ffb92014-04-03 14:43:30 -0700933 // Reversed BGP flow path for dst-TCP-port
934 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800935
Ray Milkey269ffb92014-04-03 14:43:30 -0700936 // Disable src-TCP-port, and set the dst-TCP-port
937 flowEntryMatch.disableSrcTcpUdpPort();
938 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
939 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800940
Ray Milkey269ffb92014-04-03 14:43:30 -0700941 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800942
Ray Milkey269ffb92014-04-03 14:43:30 -0700943 // TODO: Add the flow by using the new Path Intent framework
944 /*
945 if (flowManagerService.addFlow(flowPath) == null) {
946 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
947 bgpPeer.getIpAddress().getHostAddress());
948 }
949 else {
950 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
951 bgpPeer.getIpAddress().getHostAddress());
952 }
953 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700954
Ray Milkey269ffb92014-04-03 14:43:30 -0700955 /**
956 * ICMP paths between BGPd and its peers
957 */
Jonathan Hart938a0152014-04-07 18:27:31 -0700958 // match ICMP protocol BGP <- Peer
Ray Milkey269ffb92014-04-03 14:43:30 -0700959 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800960
Ray Milkey269ffb92014-04-03 14:43:30 -0700961 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
962 flowEntryMatch.disableSrcTcpUdpPort();
963 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -0800964
Ray Milkey269ffb92014-04-03 14:43:30 -0700965 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800966
Ray Milkey2476cac2014-04-08 11:03:21 -0700967 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800968
Ray Milkey269ffb92014-04-03 14:43:30 -0700969 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800970
Ray Milkey269ffb92014-04-03 14:43:30 -0700971 // TODO: Add the flow by using the new Path Intent framework
972 /*
973 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800974
Ray Milkey269ffb92014-04-03 14:43:30 -0700975 log.error("Failed to set up ICMP path BGP <- Peer {}",
976 bgpPeer.getIpAddress().getHostAddress());
977 }
978 else {
979 log.debug("Successfully set up ICMP path BGP <- Peer {}",
980 bgpPeer.getIpAddress().getHostAddress());
981 }
982 */
pingping-linba5c52f2014-02-11 16:52:01 -0800983
Jonathan Hart938a0152014-04-07 18:27:31 -0700984 // match ICMP protocol BGP -> Peer
Ray Milkey269ffb92014-04-03 14:43:30 -0700985 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800986
Ray Milkey269ffb92014-04-03 14:43:30 -0700987 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
988 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
989 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800990
Ray Milkey269ffb92014-04-03 14:43:30 -0700991 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800992
Ray Milkey269ffb92014-04-03 14:43:30 -0700993 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800994
Ray Milkey269ffb92014-04-03 14:43:30 -0700995 // TODO: Add the flow by using the new Path Intent framework
996 /*
997 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800998
Ray Milkey269ffb92014-04-03 14:43:30 -0700999 log.error("Failed to set up ICMP path BGP -> Peer {}",
1000 bgpPeer.getIpAddress().getHostAddress());
1001 }
1002 else {
1003 log.debug("Successfully set up ICMP path BGP -> Peer {}",
1004 bgpPeer.getIpAddress().getHostAddress());
1005 }
1006 */
1007 }
1008 }
pingping-linba5c52f2014-02-11 16:52:01 -08001009
Ray Milkey269ffb92014-04-03 14:43:30 -07001010 @Override
1011 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
1012 log.debug("Received ARP response: {} => {}",
1013 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001014
Ray Milkey269ffb92014-04-03 14:43:30 -07001015 /*
1016 * We synchronize on this to prevent changes to the ptree while we're pushing
1017 * flows to the switches. If the ptree changes, the ptree and switches
1018 * could get out of sync.
1019 */
1020 synchronized (this) {
1021 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001022
Ray Milkey269ffb92014-04-03 14:43:30 -07001023 if (path != null) {
1024 log.debug("Pushing path to {} at {} on {}", new Object[]{
1025 path.getDstIpAddress().getHostAddress(), macAddress,
1026 path.getDstInterface().getSwitchPort()});
Jonathan Hart938a0152014-04-07 18:27:31 -07001027 // These paths should always be to BGP peers. Paths to non-peers are
1028 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -07001029 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001030 // A path already got pushed to this endpoint while we were waiting
1031 // for ARP. We'll copy over the permanent attribute if it is set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -07001032 if (path.isPermanent()) {
1033 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1034 }
1035 } else {
1036 calculateAndPushPath(path, macAddress);
1037 pushedPaths.put(path.getDstIpAddress(), path);
1038 }
1039 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001040
Ray Milkey269ffb92014-04-03 14:43:30 -07001041 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001042
Ray Milkey269ffb92014-04-03 14:43:30 -07001043 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001044 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001045
Ray Milkey269ffb92014-04-03 14:43:30 -07001046 RibEntry rib = ptree.lookup(update.getPrefix());
1047 if (rib != null && rib.equals(update.getRibEntry())) {
1048 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1049 rib.getNextHop().getHostAddress());
Jonathan Hart938a0152014-04-07 18:27:31 -07001050 // We only push prefix flows if the prefix is still in the ptree
1051 // and the next hop is the same as our update. The prefix could
1052 // have been removed while we were waiting for the ARP, or the
1053 // next hop could have changed.
Ray Milkey7531a342014-04-11 15:08:12 -07001054 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -07001055 } else {
1056 log.debug("Received ARP response, but {},{} is no longer in ptree",
1057 update.getPrefix(), update.getRibEntry());
1058 }
1059 }
1060 }
1061 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001062
Jonathan Hart938a0152014-04-07 18:27:31 -07001063 // TODO wait the priority module of the flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001064 private void setupArpFlows() {
1065 OFMatch match = new OFMatch();
1066 match.setDataLayerType(Ethernet.TYPE_ARP);
1067 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001068
Ray Milkey269ffb92014-04-03 14:43:30 -07001069 OFFlowMod fm = new OFFlowMod();
1070 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001071
Ray Milkey269ffb92014-04-03 14:43:30 -07001072 OFActionOutput action = new OFActionOutput();
1073 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1074 action.setMaxLength((short) 0xffff);
1075 List<OFAction> actions = new ArrayList<OFAction>(1);
1076 actions.add(action);
1077 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001078
Ray Milkey269ffb92014-04-03 14:43:30 -07001079 fm.setIdleTimeout((short) 0)
1080 .setHardTimeout((short) 0)
1081 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1082 .setCookie(0)
1083 .setCommand(OFFlowMod.OFPFC_ADD)
1084 .setPriority(ARP_PRIORITY)
1085 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001086
Ray Milkey269ffb92014-04-03 14:43:30 -07001087 for (String strdpid : switches) {
1088 flowCache.write(HexString.toLong(strdpid), fm);
1089 }
1090 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001091
Jonathan Hart938a0152014-04-07 18:27:31 -07001092 // TODO need update, waiting for the priority feature from flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001093 private void setupDefaultDropFlows() {
1094 OFFlowMod fm = new OFFlowMod();
1095 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -07001096 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001097
Ray Milkey269ffb92014-04-03 14:43:30 -07001098 fm.setIdleTimeout((short) 0)
1099 .setHardTimeout((short) 0)
1100 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1101 .setCookie(0)
1102 .setCommand(OFFlowMod.OFPFC_ADD)
1103 .setPriority((short) 0)
1104 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001105
Ray Milkey269ffb92014-04-03 14:43:30 -07001106 OFFlowMod fmLLDP;
1107 OFFlowMod fmBDDP;
1108 try {
1109 fmLLDP = fm.clone();
1110 fmBDDP = fm.clone();
1111 } catch (CloneNotSupportedException e1) {
1112 log.error("Error cloning flow mod", e1);
1113 return;
1114 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001115
Ray Milkey269ffb92014-04-03 14:43:30 -07001116 OFMatch matchLLDP = new OFMatch();
1117 matchLLDP.setDataLayerType((short) 0x88cc);
1118 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1119 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001120
Ray Milkey269ffb92014-04-03 14:43:30 -07001121 OFMatch matchBDDP = new OFMatch();
1122 matchBDDP.setDataLayerType((short) 0x8942);
1123 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1124 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001125
Ray Milkey269ffb92014-04-03 14:43:30 -07001126 OFActionOutput action = new OFActionOutput();
1127 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1128 action.setMaxLength((short) 0xffff);
1129 List<OFAction> actions = new ArrayList<OFAction>(1);
1130 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001131
Ray Milkey269ffb92014-04-03 14:43:30 -07001132 fmLLDP.setActions(actions);
1133 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001134
Ray Milkey269ffb92014-04-03 14:43:30 -07001135 fmLLDP.setPriority(ARP_PRIORITY);
1136 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1137 fmBDDP.setPriority(ARP_PRIORITY);
1138 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001139
Ray Milkey269ffb92014-04-03 14:43:30 -07001140 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1141 flowModList.add(fm);
1142 flowModList.add(fmLLDP);
1143 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001144
Ray Milkey269ffb92014-04-03 14:43:30 -07001145 for (String strdpid : switches) {
1146 flowCache.write(HexString.toLong(strdpid), flowModList);
1147 }
1148 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001149
Ray Milkey269ffb92014-04-03 14:43:30 -07001150 private void beginRouting() {
1151 log.debug("Topology is now ready, beginning routing function");
1152 // TODO: Fix for the new Topology Network Graph
1153 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001154
Ray Milkey269ffb92014-04-03 14:43:30 -07001155 // Wait Pavlin's API. We need the following functions.
1156 /*setupArpFlows();
1157 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001158
Ray Milkey269ffb92014-04-03 14:43:30 -07001159 setupBgpPaths();
1160 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001161
Ray Milkey269ffb92014-04-03 14:43:30 -07001162 //Suppress link discovery on external-facing router ports
1163 for (Interface intf : interfaces.values()) {
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -07001164 linkDiscoveryService.addToSuppressLLDPs(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001165 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001166
Ray Milkey269ffb92014-04-03 14:43:30 -07001167 bgpUpdatesExecutor.execute(new Runnable() {
1168 @Override
1169 public void run() {
1170 doUpdatesThread();
1171 }
1172 });
1173 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001174
Jonathan Hart938a0152014-04-07 18:27:31 -07001175 // Before inserting the paths for BGP traffic, we should check whether
1176 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001177 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001178 // TODO: Fix the code below after topoSwitchSerice was removed
1179 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001180 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001181
Ray Milkey269ffb92014-04-03 14:43:30 -07001182 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1183 getActiveSwitches().iterator();
1184 while(activeSwitches.hasNext())
1185 {
1186 ISwitchObject switchObject = activeSwitches.next();
1187 if (switchObject.getDPID().equals(dpid)) {
1188 break;
1189 }
1190 if(activeSwitches.hasNext() == false) {
1191 log.debug("Not all switches are here yet");
1192 return;
1193 }
1194 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001195 }
1196 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001197 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001198 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001199
Jonathan Hart938a0152014-04-07 18:27:31 -07001200 // Actually we only need to go half way round to verify full mesh connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001201 private void checkTopologyReady() {
1202 for (Interface dstInterface : interfaces.values()) {
1203 for (Interface srcInterface : interfaces.values()) {
1204 if (dstInterface.equals(srcInterface)) {
1205 continue;
1206 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001207
Ray Milkey269ffb92014-04-03 14:43:30 -07001208 // TODO: Fix for the new Topology Network Graph
1209 /*
1210 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1211 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001212
Ray Milkey269ffb92014-04-03 14:43:30 -07001213 if (shortestPath == null){
1214 log.debug("Shortest path between {} and {} not found",
1215 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1216 return;
1217 }
1218 */
1219 }
1220 }
1221 topologyReady = true;
1222 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001223
Ray Milkey269ffb92014-04-03 14:43:30 -07001224 private void checkStatus() {
1225 if (!switchesConnected) {
1226 checkSwitchesConnected();
1227 }
1228 boolean oldTopologyReadyStatus = topologyReady;
1229 if (switchesConnected && !topologyReady) {
1230 checkTopologyReady();
1231 }
1232 if (!oldTopologyReadyStatus && topologyReady) {
1233 beginRouting();
1234 }
1235 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001236
Ray Milkey269ffb92014-04-03 14:43:30 -07001237 private void doUpdatesThread() {
1238 boolean interrupted = false;
1239 try {
1240 while (true) {
1241 try {
1242 RibUpdate update = ribUpdates.take();
1243 switch (update.getOperation()) {
1244 case UPDATE:
1245 if (validateUpdate(update)) {
1246 processRibAdd(update);
1247 } else {
1248 log.debug("Rib UPDATE out of order: {} via {}",
1249 update.getPrefix(), update.getRibEntry().getNextHop());
1250 }
1251 break;
1252 case DELETE:
1253 if (validateUpdate(update)) {
1254 processRibDelete(update);
1255 } else {
1256 log.debug("Rib DELETE out of order: {} via {}",
1257 update.getPrefix(), update.getRibEntry().getNextHop());
1258 }
1259 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -07001260 default:
1261 log.error("Unknown operation {}", update.getOperation());
1262 break;
Ray Milkey269ffb92014-04-03 14:43:30 -07001263 }
1264 } catch (InterruptedException e) {
1265 log.debug("Interrupted while taking from updates queue", e);
1266 interrupted = true;
1267 } catch (Exception e) {
1268 log.debug("exception", e);
1269 }
1270 }
1271 } finally {
1272 if (interrupted) {
1273 Thread.currentThread().interrupt();
1274 }
1275 }
1276 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001277
Ray Milkey269ffb92014-04-03 14:43:30 -07001278 private boolean validateUpdate(RibUpdate update) {
1279 RibEntry newEntry = update.getRibEntry();
1280 RibEntry oldEntry = ptree.lookup(update.getPrefix());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001281
Ray Milkey269ffb92014-04-03 14:43:30 -07001282 //If there is no existing entry we must assume this is the most recent
1283 //update. However this might not always be the case as we might have a
1284 //POST then DELETE reordering.
1285 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1286 if (oldEntry == null) {
1287 return true;
1288 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001289
Ray Milkey269ffb92014-04-03 14:43:30 -07001290 // This handles the case where routes are gathered in the initial
1291 // request because they don't have sequence number info
1292 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1293 return true;
1294 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001295
Ray Milkey269ffb92014-04-03 14:43:30 -07001296 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1297 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001298 }
Ray Milkey4985f212014-04-10 16:57:05 -07001299
1300 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
1301 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -07001302 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001303
Ray Milkey269ffb92014-04-03 14:43:30 -07001304 // The code below should be reimplemented after removal of Floodlight's
1305 // ITopologyService API. It should be implemented on top of network graph
1306 // notifications. (It was pretty hacky anyway...)
1307 /*
1308 @Override
1309 public void topologyChanged() {
1310 if (topologyReady) {
1311 return;
1312 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001313
Ray Milkey269ffb92014-04-03 14:43:30 -07001314 boolean refreshNeeded = false;
1315 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1316 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1317 //We don't need to recalculate anything for just link updates
1318 //They happen very frequently
1319 refreshNeeded = true;
1320 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001321
Ray Milkey269ffb92014-04-03 14:43:30 -07001322 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001323
Ray Milkey269ffb92014-04-03 14:43:30 -07001324 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1325 synchronized (linkUpdates) {
1326 linkUpdates.add(ldu);
1327 }
1328 }
1329 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001330
Ray Milkey269ffb92014-04-03 14:43:30 -07001331 if (refreshNeeded && !topologyReady){
1332 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1333 }
1334 }
1335 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001336
Ray Milkey269ffb92014-04-03 14:43:30 -07001337 @Override
1338 public void addedSwitch(IOFSwitch sw) {
1339 if (!topologyReady) {
1340 sw.clearAllFlowMods();
1341 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001342
Ray Milkey269ffb92014-04-03 14:43:30 -07001343 flowCache.switchConnected(sw);
1344 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001345
Ray Milkey269ffb92014-04-03 14:43:30 -07001346 @Override
1347 public void removedSwitch(IOFSwitch sw) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001348 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001349 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001350
Ray Milkey269ffb92014-04-03 14:43:30 -07001351 @Override
1352 public void switchPortChanged(Long switchId) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001353 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001354 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001355
Ray Milkey269ffb92014-04-03 14:43:30 -07001356 @Override
1357 public String getName() {
Jonathan Hart8f6dc092014-04-18 15:56:43 -07001358 return "SdnIp";
Ray Milkey269ffb92014-04-03 14:43:30 -07001359 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001360
Ray Milkey269ffb92014-04-03 14:43:30 -07001361 /*
1362 * IConfigInfoService methods
1363 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001364
Ray Milkey269ffb92014-04-03 14:43:30 -07001365 @Override
1366 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hart5e54f2e2014-04-17 13:43:40 -07001367 Interface intf = interfacePtree.match(new Prefix(address.getAddress(), 32));
Ray Milkey269ffb92014-04-03 14:43:30 -07001368 return (intf != null && intf.getIpAddress().equals(address));
1369 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001370
Ray Milkey269ffb92014-04-03 14:43:30 -07001371 @Override
1372 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hart5e54f2e2014-04-17 13:43:40 -07001373 Interface intf = interfacePtree.match(new Prefix(address.getAddress(), 32));
Ray Milkey269ffb92014-04-03 14:43:30 -07001374 return (intf != null && !intf.getIpAddress().equals(address));
1375 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001376
Ray Milkey269ffb92014-04-03 14:43:30 -07001377 @Override
1378 public boolean fromExternalNetwork(long inDpid, short inPort) {
1379 for (Interface intf : interfaces.values()) {
1380 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1381 return true;
1382 }
1383 }
1384 return false;
1385 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001386
Ray Milkey269ffb92014-04-03 14:43:30 -07001387 @Override
1388 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hart5e54f2e2014-04-17 13:43:40 -07001389 return interfacePtree.match(new Prefix(dstIpAddress.getAddress(), 32));
Ray Milkey269ffb92014-04-03 14:43:30 -07001390 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001391
Ray Milkey269ffb92014-04-03 14:43:30 -07001392 @Override
1393 public boolean hasLayer3Configuration() {
1394 return !interfaces.isEmpty();
1395 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001396
Ray Milkey269ffb92014-04-03 14:43:30 -07001397 @Override
1398 public MACAddress getRouterMacAddress() {
1399 return bgpdMacAddress;
1400 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001401
Ray Milkey269ffb92014-04-03 14:43:30 -07001402 @Override
1403 public short getVlan() {
1404 return vlan;
1405 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001406}