blob: d6713d549c5988e348381ce2c066a5416fdcbbda [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;
Komal Shah399a2922014-05-28 01:57:40 -070039import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart23701d12014-04-03 10:45:48 -070040import net.onrc.onos.core.util.Dpid;
Yuta HIGUCHIfb564502014-06-16 21:29:00 -070041import net.onrc.onos.core.util.PortNumber;
Jonathan Hart23701d12014-04-03 10:45:48 -070042import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080043import net.sf.json.JSONArray;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070044import net.sf.json.JSONException;
pingping-line2a09ca2013-03-23 09:33:58 +080045import net.sf.json.JSONObject;
46import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080047
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070048import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120049import org.codehaus.jackson.JsonParseException;
50import org.codehaus.jackson.map.JsonMappingException;
51import org.codehaus.jackson.map.ObjectMapper;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070052import org.projectfloodlight.openflow.protocol.OFPortDesc;
pingping-lina2cbfad2013-03-07 08:39:21 +080053import org.slf4j.Logger;
54import org.slf4j.LoggerFactory;
55
Jonathan Hart4dfc3652013-08-02 20:22:36 +120056import com.google.common.collect.HashMultimap;
57import com.google.common.collect.Multimaps;
58import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120059import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120060import com.google.common.util.concurrent.ThreadFactoryBuilder;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070061import com.googlecode.concurrenttrees.radix.RadixTree;
62import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
63import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
64import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120065
Jonathan Hart8f6dc092014-04-18 15:56:43 -070066public class SdnIp implements IFloodlightModule, ISdnIpService,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070067 IArpRequester, IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070068
Jonathan Hart8f6dc092014-04-18 15:56:43 -070069 private static final Logger log = LoggerFactory.getLogger(SdnIp.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080070
Ray Milkey269ffb92014-04-03 14:43:30 -070071 private IFloodlightProviderService floodlightProvider;
72 private ILinkDiscoveryService linkDiscoveryService;
73 private IRestApiService restApi;
74 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070075
Jonathan Hartf6978ce2014-06-23 11:20:04 -070076 private InvertedRadixTree<RibEntry> bgpRoutes;
77 private InvertedRadixTree<Interface> interfaceRoutes;
78
Ray Milkey269ffb92014-04-03 14:43:30 -070079 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070080
Ray Milkey269ffb92014-04-03 14:43:30 -070081 private String bgpdRestIp;
82 private String routerId;
Ray Milkey5df613b2014-04-15 10:50:56 -070083 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
84 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070085
Komal Shah399a2922014-05-28 01:57:40 -070086 /* ShortestPath Intent Variables */
Sho SHIMIZU9ec39822014-07-10 17:15:12 -070087 private final String caller = "SdnIp";
Komal Shah399a2922014-05-28 01:57:40 -070088 private IControllerRegistryService controllerRegistryService;
89 private IPathCalcRuntimeService pathRuntime;
90 /* Shortest Intent Path Variables */
91
Ray Milkey2476cac2014-04-08 11:03:21 -070092 private static final short ARP_PRIORITY = 20;
Ray Milkey5d406012014-04-08 14:44:41 -070093
Jonathan Hart938a0152014-04-07 18:27:31 -070094 // The fields below are unused after the move to FlowManager.
95 // Remove them if no longer needed.
96 /*
97 // We need to identify our flows somehow, in lieu of an OS-wide mechanism
98 // to hand out cookie IDs to prevent conflicts.
99 private static final long APP_COOKIE = 0xa0000000000000L;
100 // Cookie for flows that do L2 forwarding within SDN domain to egress routers
101 private static final long L2_FWD_COOKIE = APP_COOKIE + 1;
102 // Cookie for flows in ingress switches that rewrite the MAC address
103 private static final long MAC_RW_COOKIE = APP_COOKIE + 2;
104 // Cookie for flows that setup BGP paths
105 private static final long BGP_COOKIE = APP_COOKIE + 3;
106 // Forwarding uses priority 0, and the mac rewrite entries in ingress switches
107 // need to be higher priority than this otherwise the rewrite may not get done
108 private static final short SDNIP_PRIORITY = 10;
109 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700110
Ray Milkey2476cac2014-04-08 11:03:21 -0700111 private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700112
Jonathan Hart938a0152014-04-07 18:27:31 -0700113 private static final int TOPO_DETECTION_WAIT = 2; // seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700114
Jonathan Hart938a0152014-04-07 18:27:31 -0700115 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700116 private List<String> switches;
117 private Map<String, Interface> interfaces;
118 private Map<InetAddress, BgpPeer> bgpPeers;
119 private SwitchPort bgpdAttachmentPoint;
120 private MACAddress bgpdMacAddress;
121 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700122
Jonathan Hart938a0152014-04-07 18:27:31 -0700123 // True when all switches have connected
Ray Milkey269ffb92014-04-03 14:43:30 -0700124 private volatile boolean switchesConnected = false;
Jonathan Hart938a0152014-04-07 18:27:31 -0700125 // True when we have a full mesh of shortest paths between gateways
Ray Milkey269ffb92014-04-03 14:43:30 -0700126 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200127
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700128 // private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700129
Ray Milkey269ffb92014-04-03 14:43:30 -0700130 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700131
Ray Milkey269ffb92014-04-03 14:43:30 -0700132 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700133
Ray Milkey269ffb92014-04-03 14:43:30 -0700134 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700135
Ray Milkey269ffb92014-04-03 14:43:30 -0700136 private Map<InetAddress, Path> pushedPaths;
137 private Map<Prefix, Path> prefixToPath;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700138 // private Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hart4de98c32014-08-11 17:03:25 -0700139 //private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700140
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700141 // XXX FlowCache has been removed
142 //private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700143
Ray Milkey269ffb92014-04-03 14:43:30 -0700144 // TODO: Fix for the new Topology Network Graph
145 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700146
Jonathan Hart284e70f2014-07-05 12:32:51 -0700147 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700148 private class TopologyChangeDetector implements Runnable {
149 @Override
150 public void run() {
151 log.debug("Running topology change detection task");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700152 // TODO: Fix the code below after topoLinkService was removed
Ray Milkey269ffb92014-04-03 14:43:30 -0700153 synchronized (linkUpdates) {
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700154
Ray Milkey269ffb92014-04-03 14:43:30 -0700155 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700156
Ray Milkey269ffb92014-04-03 14:43:30 -0700157 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700158
Ray Milkey269ffb92014-04-03 14:43:30 -0700159 Iterator<LDUpdate> it = linkUpdates.iterator();
160 while (it.hasNext()){
161 LDUpdate ldu = it.next();
162 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
163 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700164
Ray Milkey269ffb92014-04-03 14:43:30 -0700165 if (activeLinks.contains(l)){
166 it.remove();
167 }
168 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700169 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700170
Ray Milkey269ffb92014-04-03 14:43:30 -0700171 if (!topologyReady) {
172 if (linkUpdates.isEmpty()) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700173 // All updates have been seen in network map.
174 // We can check if topology is ready
Ray Milkey269ffb92014-04-03 14:43:30 -0700175 log.debug("No known changes outstanding. Checking topology now");
176 checkStatus();
177 } else {
Jonathan Hart938a0152014-04-07 18:27:31 -0700178 // We know of some link updates that haven't propagated to the database yet
Ray Milkey269ffb92014-04-03 14:43:30 -0700179 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
180 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
181 }
182 }
183 }
184 }
Jonathan Hart284e70f2014-07-05 12:32:51 -0700185 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700186
Ray Milkey269ffb92014-04-03 14:43:30 -0700187 private void readConfiguration(String configFilename) {
188 File gatewaysFile = new File(configFilename);
189 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700190
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 try {
192 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700193
Ray Milkey269ffb92014-04-03 14:43:30 -0700194 switches = config.getSwitches();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700195 interfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700196 for (Interface intf : config.getInterfaces()) {
197 interfaces.put(intf.getName(), intf);
198 }
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700199 bgpPeers = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700200 for (BgpPeer peer : config.getPeers()) {
201 bgpPeers.put(peer.getIpAddress(), peer);
202 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700203
Ray Milkey269ffb92014-04-03 14:43:30 -0700204 bgpdAttachmentPoint = new SwitchPort(
205 new Dpid(config.getBgpdAttachmentDpid()),
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700206 PortNumber.uint16(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700207
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 bgpdMacAddress = config.getBgpdMacAddress();
209 vlan = config.getVlan();
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -0700210 } catch (JsonParseException | JsonMappingException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700211 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700212 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700213 } catch (IOException e) {
214 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700215 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700216 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700217
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700218 // Populate the interface Patricia Tree
Ray Milkey269ffb92014-04-03 14:43:30 -0700219 for (Interface intf : interfaces.values()) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700220 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
221 intf.getPrefixLength());
222 interfaceRoutes.put(prefix.toBinaryString(), intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700223 }
224 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700225
Ray Milkey269ffb92014-04-03 14:43:30 -0700226 @Override
227 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700228 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700229 l.add(ISdnIpService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700230 l.add(IConfigInfoService.class);
231 return l;
232 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700233
Ray Milkey269ffb92014-04-03 14:43:30 -0700234 @Override
235 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700236 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700237 m.put(ISdnIpService.class, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700238 m.put(IConfigInfoService.class, this);
239 return m;
240 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800241
Ray Milkey269ffb92014-04-03 14:43:30 -0700242 @Override
243 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700244 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700245 l.add(IFloodlightProviderService.class);
246 l.add(IRestApiService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700247 l.add(IControllerRegistryService.class);
248 l.add(IPathCalcRuntimeService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700249 return l;
250 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700251
Ray Milkey269ffb92014-04-03 14:43:30 -0700252 @Override
253 public void init(FloodlightModuleContext context)
254 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700255
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700256 bgpRoutes = new ConcurrentInvertedRadixTree<>(
257 new DefaultByteArrayNodeFactory());
258 interfaceRoutes = new ConcurrentInvertedRadixTree<>(
259 new DefaultByteArrayNodeFactory());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700260
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700261 ribUpdates = new LinkedBlockingQueue<>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700262
Ray Milkey269ffb92014-04-03 14:43:30 -0700263 // Register floodlight provider and REST handler.
264 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
265 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
266 restApi = context.getServiceImpl(IRestApiService.class);
267 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800268
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700269 controllerRegistryService = context
270 .getServiceImpl(IControllerRegistryService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700271 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700272
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700273 // ScheduledExecutorService executor =
274 // Executors.newScheduledThreadPool(1);
275 // topologyChangeDetectorTask = new SingletonTask(executor, new
276 // TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700277
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700278 pathsWaitingOnArp = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700279 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
280 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700281
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700282 pushedPaths = new HashMap<>();
283 prefixToPath = new HashMap<>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700284 // pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
Jonathan Hart4de98c32014-08-11 17:03:25 -0700285 // pushedFlowIds = HashMultimap.create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700286
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700287 //flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700288
Ray Milkey269ffb92014-04-03 14:43:30 -0700289 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
290 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700291
Jonathan Hart938a0152014-04-07 18:27:31 -0700292 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700293 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
294 if (bgpdRestIp == null) {
295 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700296 throw new ConfigurationRuntimeException(
297 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700298 } else {
299 log.info("BgpdRestIp set to {}", bgpdRestIp);
300 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700301
Ray Milkey269ffb92014-04-03 14:43:30 -0700302 routerId = context.getConfigParams(this).get("RouterId");
303 if (routerId == null) {
304 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700305 throw new ConfigurationRuntimeException(
306 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700307 } else {
308 log.info("RouterId set to {}", routerId);
309 }
pingping-linba5c52f2014-02-11 16:52:01 -0800310
Ray Milkey269ffb92014-04-03 14:43:30 -0700311 String configFilenameParameter = context.getConfigParams(this).get("configfile");
312 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700313 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700314 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700315 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700316
Ray Milkey5df613b2014-04-15 10:50:56 -0700317 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700318 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700319
Ray Milkey269ffb92014-04-03 14:43:30 -0700320 @Override
321 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700322 restApi.addRestletRoutable(new SdnIpWebRoutable());
Komal Shah399a2922014-05-28 01:57:40 -0700323 restApi.addRestletRoutable(new SdnIpWebRoutableNew());
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 Hartf6978ce2014-06-23 11:20:04 -0700331 public RadixTree<RibEntry> getPtree() {
332 return bgpRoutes;
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 clearPtree() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700337 log.warn("Clear table operation not supported");
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
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700358 try {
359 response = response.replaceAll("\"", "'");
360 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
361 JSONArray ribArray = jsonObj.getJSONArray("rib");
362 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700363
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700364 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700365
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700366 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700367
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700368 for (int j = 0; j < size; j++) {
369 JSONObject ribEntry = ribArray.getJSONObject(j);
370 String prefix = ribEntry.getString("prefix");
371 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700372
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700373 // Insert each rib entry into the local rib
374 String[] substring = prefix.split("/");
375 String prefix1 = substring[0];
376 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700377
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700378 Prefix p;
379 try {
380 p = new Prefix(prefix1, Integer.parseInt(mask1));
381 } catch (NumberFormatException e) {
382 log.warn("Wrong mask format in RIB JSON: {}", mask1);
383 continue;
384 } catch (IllegalArgumentException e1) {
385 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
386 continue;
387 }
388
389 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
390
391 try {
392 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
393 } catch (InterruptedException e) {
394 log.debug("Interrupted while pushing onto update queue");
395 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700396 }
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700397 } catch (JSONException e) {
398 // TODO don't parse JSON manually
399 log.error("Error parsing inital route table JSON:", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700400 }
401 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700402
Ray Milkey269ffb92014-04-03 14:43:30 -0700403 @Override
404 public void newRibUpdate(RibUpdate update) {
405 try {
406 ribUpdates.put(update);
407 } catch (InterruptedException e) {
408 log.debug("Interrupted while putting on ribUpdates queue", e);
409 Thread.currentThread().interrupt();
410 }
411 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700412
Sho SHIMIZUba372192014-07-10 08:59:57 -0700413 private void processRibAdd(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700414 synchronized (this) {
415 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700416
Jonathan Hart938a0152014-04-07 18:27:31 -0700417 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700418
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700419 RibEntry rib = bgpRoutes.put(prefix.toBinaryString(), update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700420
Jonathan Hart938a0152014-04-07 18:27:31 -0700421 if (rib != null && !rib.equals(update.getRibEntry())) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700422 // There was an existing nexthop for this prefix. This update
423 // supersedes that,
424 // so we need to remove the old flows for this prefix from the
425 // switches
Ray Milkey7531a342014-04-11 15:08:12 -0700426 executeDeletePrefix(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700427 }
Ray Milkey5d406012014-04-08 14:44:41 -0700428
Jonathan Hart938a0152014-04-07 18:27:31 -0700429 if (update.getRibEntry().getNextHop().equals(
430 InetAddresses.forString("0.0.0.0"))) {
431 // Route originated by SDN domain
432 // We don't handle these at the moment
433 log.debug("Own route {} to {}", prefix,
434 update.getRibEntry().getNextHop().getHostAddress());
435 return;
436 }
Ray Milkey5d406012014-04-08 14:44:41 -0700437
Ray Milkey7531a342014-04-11 15:08:12 -0700438 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700439 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700440 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700441
Ray Milkey7531a342014-04-11 15:08:12 -0700442 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700443 // TODO: Fix the code below. Note that "deviceStorage" was removed.
444
445 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700446 Prefix prefix = update.getPrefix();
447 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700448
Ray Milkey269ffb92014-04-03 14:43:30 -0700449 InetAddress dstIpAddress = rib.getNextHop();
450 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800451
Ray Milkey269ffb92014-04-03 14:43:30 -0700452 // See if we know the MAC address of the next hop
453 // 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 -0700454 IDeviceObject nextHopDevice =
455 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700456
Ray Milkey269ffb92014-04-03 14:43:30 -0700457 if (nextHopDevice == null){
458 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
459 prefixesWaitingOnArp.put(dstIpAddress,
460 new RibUpdate(Operation.UPDATE, prefix, rib));
461 proxyArp.sendArpRequest(dstIpAddress, this, true);
462 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800463
Ray Milkey269ffb92014-04-03 14:43:30 -0700464 }
465 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700466
Ray Milkey269ffb92014-04-03 14:43:30 -0700467 // Find the attachment point (egress interface) of the next hop
468 Interface egressInterface = null;
469 if (bgpPeers.containsKey(dstIpAddress)) {
470 //Route to a peer
471 log.debug("Route to peer {}", dstIpAddress);
472 BgpPeer peer = bgpPeers.get(dstIpAddress);
473 egressInterface = interfaces.get(peer.getInterfaceName());
474 } else {
475 //Route to non-peer
476 log.debug("Route to non-peer {}", dstIpAddress);
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700477 egressInterface = interfacePtree.match(
Ray Milkey269ffb92014-04-03 14:43:30 -0700478 new Prefix(dstIpAddress.getAddress(), 32));
479 if (egressInterface == null) {
480 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
481 return;
482 }
483 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700484
Ray Milkey269ffb92014-04-03 14:43:30 -0700485 if (nextHopMacAddress == null) {
486 prefixesWaitingOnArp.put(dstIpAddress,
487 new RibUpdate(Operation.UPDATE, prefix, rib));
488 proxyArp.sendArpRequest(dstIpAddress, this, true);
489 return;
490 } else {
491 if (!bgpPeers.containsKey(dstIpAddress)) {
492 //If the prefix is for a non-peer we need to ensure there's a path,
493 //and push one if there isn't.
494 Path path = pushedPaths.get(dstIpAddress);
495 if (path == null) {
496 path = new Path(egressInterface, dstIpAddress);
497 calculateAndPushPath(path, nextHopMacAddress);
498 pushedPaths.put(dstIpAddress, path);
499 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700500
Ray Milkey269ffb92014-04-03 14:43:30 -0700501 path.incrementUsers();
502 prefixToPath.put(prefix, path);
503 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700504
Ray Milkey269ffb92014-04-03 14:43:30 -0700505 //For all prefixes we need to add the first-hop mac-rewriting flows
506 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
507 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700508 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700509 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700510
Ray Milkey269ffb92014-04-03 14:43:30 -0700511 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700512 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix to
513 * all other border switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700514 */
515 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700516 MACAddress nextHopMacAddress) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700517 log.debug("Adding flows for prefix {}, next hop mac {}",
518 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700519
Jonathan Hart4de98c32014-08-11 17:03:25 -0700520 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700521 FlowPath flowPath = new FlowPath();
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700522 flowPath.setInstallerId(callerId);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700523
Ray Milkey269ffb92014-04-03 14:43:30 -0700524 // Set flowPath FlowPathType and FlowPathUserState
525 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
526 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800527
Ray Milkey269ffb92014-04-03 14:43:30 -0700528 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
529 // only to the first-host switches
530 FlowPathFlags flowPathFlags = new FlowPathFlags();
531 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
532 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800533
Ray Milkey269ffb92014-04-03 14:43:30 -0700534 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700535 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700536 new SwitchPort(new Dpid(egressInterface.getDpid()),
537 new PortNumber(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800538
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700539 // We only need one flow mod per switch, so pick one interface on each
540 // switch
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700541 Map<Long, Interface> srcInterfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700542 for (Interface intf : interfaces.values()) {
543 if (!srcInterfaces.containsKey(intf.getDpid())
544 && !intf.equals(egressInterface)) {
545 srcInterfaces.put(intf.getDpid(), intf);
546 }
547 }
548 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800549
Ray Milkey269ffb92014-04-03 14:43:30 -0700550 if (egressInterface.equals(srcInterface)) {
551 continue;
552 }
pingping-linba5c52f2014-02-11 16:52:01 -0800553
Ray Milkey269ffb92014-04-03 14:43:30 -0700554 // Create flowPath FlowId
555 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800556
Ray Milkey269ffb92014-04-03 14:43:30 -0700557 // Create DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700558 SwitchPort srcPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700559 new SwitchPort(new Dpid(srcInterface.getDpid()),
560 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800561
Ray Milkey269ffb92014-04-03 14:43:30 -0700562 DataPath dataPath = new DataPath();
563 dataPath.setSrcPort(srcPort);
564 dataPath.setDstPort(dstPort);
565 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800566
Ray Milkey269ffb92014-04-03 14:43:30 -0700567 // Create flow path matching condition(s): IPv4 Prefix
568 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700569 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700570 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
571 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
572 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300573
Jonathan Hart4de98c32014-08-11 17:03:25 -0700574 *
Ray Milkey269ffb92014-04-03 14:43:30 -0700575 * Create the Flow Entry Action(s): dst-MAC rewrite action
Jonathan Hart4de98c32014-08-11 17:03:25 -0700576 *
Ray Milkey269ffb92014-04-03 14:43:30 -0700577 FlowEntryActions flowEntryActions = new FlowEntryActions();
578 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
579 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
580 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
581 flowEntryActions.addAction(flowEntryAction1);
582 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800583
Ray Milkey269ffb92014-04-03 14:43:30 -0700584 // Flow Path installation, only to first hop switches
585 // TODO: Add the flow by using the new Path Intent framework
586 /*
587 if (flowManagerService.addFlow(flowPath) == null) {
588 log.error("Failed to install flow path to the first hop for " +
589 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
590 nextHopMacAddress);
591 }
592 else {
593 log.debug("Successfully installed flow path to the first hop " +
594 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
595 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800596
Ray Milkey269ffb92014-04-03 14:43:30 -0700597 pushedFlowIds.put(prefix, flowPath.flowId());
598 }
Jonathan Hart4de98c32014-08-11 17:03:25 -0700599
Ray Milkey269ffb92014-04-03 14:43:30 -0700600 }
Jonathan Hart4de98c32014-08-11 17:03:25 -0700601 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700602 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700603
Sho SHIMIZUba372192014-07-10 08:59:57 -0700604 private void processRibDelete(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700605 synchronized (this) {
606 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700607
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700608 // if (ptree.remove(prefix, update.getRibEntry())) {
609 // TODO check the change of logic here - remove doesn't check that
610 // the
611 // rib entry was what we expected (and we can't do this
612 // concurrently)
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700613 if (bgpRoutes.remove(prefix.toBinaryString())) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700614 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700615 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700616 * If no entry was removed, the <prefix, nexthop> wasn't there so
617 * it's probably already been removed and we don't need to do anything
618 */
Ray Milkey7531a342014-04-11 15:08:12 -0700619 executeDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart938a0152014-04-07 18:27:31 -0700620 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700621 }
622 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700623
Ray Milkey7531a342014-04-11 15:08:12 -0700624 private void executeDeletePrefix(Prefix prefix, RibEntry ribEntry) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700625 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700626
Ray Milkey269ffb92014-04-03 14:43:30 -0700627 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700628
Ray Milkey269ffb92014-04-03 14:43:30 -0700629 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
630 log.debug("Getting path for route with non-peer nexthop");
631 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700632
Ray Milkey269ffb92014-04-03 14:43:30 -0700633 if (path != null) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700634 // path could be null if we added to the Ptree but didn't push
635 // flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700636
Ray Milkey269ffb92014-04-03 14:43:30 -0700637 path.decrementUsers();
638 if (path.getUsers() <= 0 && !path.isPermanent()) {
639 deletePath(path);
640 pushedPaths.remove(path.getDstIpAddress());
641 }
642 }
643 }
644 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700645
Ray Milkey269ffb92014-04-03 14:43:30 -0700646 // TODO have not tested this module
647 private void deletePrefixFlows(Prefix prefix) {
648 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700649
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700650 //
651 // TODO: Delete the flow by using the new Path Intent framework
652 // NOTE: During the refactoring of the code below, if obtaining
653 // the values of the removed flowIds is needed, the first
654 // removeAll() statement should be replaced with the second removeAll()
655 // statement.
656 //
Jonathan Hart4de98c32014-08-11 17:03:25 -0700657 // pushedFlowIds.removeAll(prefix);
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700658 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700659 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
660 for (FlowId flowId : flowIds) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700661 if (log.isTraceEnabled()) {
662 //Trace the flow status by flowPath in the switch before deleting it
663 log.trace("Pushing a DELETE flow mod to flowPath : {}",
664 flowManagerService.getFlow(flowId).toString());
665 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700666
Ray Milkey269ffb92014-04-03 14:43:30 -0700667 if( flowManagerService.deleteFlow(flowId))
668 {
669 log.debug("Successfully deleted FlowId: {}",flowId);
670 }
671 else
672 {
673 log.debug("Failed to delete FlowId: {}",flowId);
674 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700675 }
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700676 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700677 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700678
Ray Milkey269ffb92014-04-03 14:43:30 -0700679 // TODO need to record the path and then delete here
680 private void deletePath(Path path) {
681 log.debug("Deleting flows for path to {}",
682 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700683
Ray Milkey269ffb92014-04-03 14:43:30 -0700684 // TODO need update
685 /*for (PushedFlowMod pfm : path.getFlowMods()) {
686 if (log.isTraceEnabled()) {
687 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
688 new Object[] {HexString.toHexString(pfm.getDpid()),
689 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
690 });
691 }
pingping-linba5c52f2014-02-11 16:52:01 -0800692
Ray Milkey269ffb92014-04-03 14:43:30 -0700693 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
694 }*/
695 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700696
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700697 // TODO test next-hop changes
698 // TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800699
Ray Milkey269ffb92014-04-03 14:43:30 -0700700 /**
701 * On startup, we need to calculate a full mesh of paths between all gateway
Ray Milkeyb41100a2014-04-10 10:42:15 -0700702 * switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700703 */
704 private void setupFullMesh() {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700705 // TODO: Fix the code below. Note that "deviceStorage" was removed.
706
707 /*
708
Ray Milkey269ffb92014-04-03 14:43:30 -0700709 //For each border router, calculate and install a path from every other
710 //border switch to said border router. However, don't install the entry
711 //in to the first hop switch, as we need to install an entry to rewrite
712 //for each prefix received. This will be done later when prefixes have
713 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700714
Ray Milkey269ffb92014-04-03 14:43:30 -0700715 for (BgpPeer peer : bgpPeers.values()) {
716 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700717
Ray Milkey269ffb92014-04-03 14:43:30 -0700718 //We know there's not already a Path here pushed, because this is
719 //called before all other routing
720 Path path = new Path(peerInterface, peer.getIpAddress());
721 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700722
Ray Milkey269ffb92014-04-03 14:43:30 -0700723 //See if we know the MAC address of the peer. If not we can't
724 //do anything until we learn it
Ray Milkey269ffb92014-04-03 14:43:30 -0700725 MACAddress macAddress = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700726 IDeviceObject nextHopDevice =
727 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800728
Ray Milkey269ffb92014-04-03 14:43:30 -0700729 if(nextHopDevice == null){
730 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
731 //Put in the pending paths list first
732 pathsWaitingOnArp.put(peer.getIpAddress(), path);
733 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
734 continue;
735 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700736
Ray Milkey269ffb92014-04-03 14:43:30 -0700737 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
pingping-linba5c52f2014-02-11 16:52:01 -0800738
Ray Milkey269ffb92014-04-03 14:43:30 -0700739 if (macAddress == null) {
740 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
741 //Put in the pending paths list first
742 pathsWaitingOnArp.put(peer.getIpAddress(), path);
743 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
744 continue;
745 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700746
Ray Milkey269ffb92014-04-03 14:43:30 -0700747 //If we know the MAC, lets go ahead and push the paths to this peer
748 calculateAndPushPath(path, macAddress);
749 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700750 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700751 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700752
Ray Milkey269ffb92014-04-03 14:43:30 -0700753 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart4de98c32014-08-11 17:03:25 -0700754 // Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700755
Ray Milkey269ffb92014-04-03 14:43:30 -0700756 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
757 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800758
Jonathan Hart4de98c32014-08-11 17:03:25 -0700759 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700760 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800761
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700762 flowPath.setInstallerId(callerId);
pingping-linba5c52f2014-02-11 16:52:01 -0800763
Ray Milkey269ffb92014-04-03 14:43:30 -0700764 // Set flowPath FlowPathType and FlowPathUserState
765 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
766 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800767
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700768 // Insert the dest-mac based forwarding flow entry to the non-first-hop
769 // switches
Ray Milkey269ffb92014-04-03 14:43:30 -0700770 FlowPathFlags flowPathFlags = new FlowPathFlags();
771 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
772 flowPath.setFlowPathFlags(flowPathFlags);
773
774 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700775 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700776 new SwitchPort(new Dpid(dstInterface.getDpid()),
777 new PortNumber(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800778
Ray Milkey269ffb92014-04-03 14:43:30 -0700779 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800780
Ray Milkey269ffb92014-04-03 14:43:30 -0700781 if (dstInterface.equals(srcInterface)) {
782 continue;
783 }
pingping-linba5c52f2014-02-11 16:52:01 -0800784
Ray Milkey269ffb92014-04-03 14:43:30 -0700785 // Create flowPath FlowId
786 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800787
Ray Milkey269ffb92014-04-03 14:43:30 -0700788 // Create the DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700789 SwitchPort srcPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700790 new SwitchPort(new Dpid(srcInterface.getDpid()),
791 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800792
Ray Milkey269ffb92014-04-03 14:43:30 -0700793 DataPath dataPath = new DataPath();
794 dataPath.setSrcPort(srcPort);
795 dataPath.setDstPort(dstPort);
796 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800797
Ray Milkey269ffb92014-04-03 14:43:30 -0700798 // Create the Flow Path Match condition(s)
799 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700800 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700801 flowEntryMatch.enableDstMac(dstMacAddress);
802 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800803
Ray Milkey269ffb92014-04-03 14:43:30 -0700804 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700805 // Shortest Path Flow, and is always the last action for the Flow
806 // Entries
Ray Milkey269ffb92014-04-03 14:43:30 -0700807 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
808 // TODO: Add the flow by using the new Path Intent framework
Jonathan Hart4de98c32014-08-11 17:03:25 -0700809
Ray Milkey269ffb92014-04-03 14:43:30 -0700810 if (flowManagerService.addFlow(flowPath) == null) {
811 log.error("Failed to set up MAC based forwarding path to {}, {}",
812 path.getDstIpAddress().getHostAddress(),dstMacAddress);
813 }
814 else {
815 log.debug("Successfully set up MAC based forwarding path to {}, {}",
816 path.getDstIpAddress().getHostAddress(),dstMacAddress);
817 }
Jonathan Hart4de98c32014-08-11 17:03:25 -0700818
Ray Milkey269ffb92014-04-03 14:43:30 -0700819 }
Jonathan Hart4de98c32014-08-11 17:03:25 -0700820 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700821 }
pingping-linba5c52f2014-02-11 16:52:01 -0800822
Komal Shah399a2922014-05-28 01:57:40 -0700823 @Override
824 public void beginRoutingNew() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700825 setupBgpPathsNew();
Komal Shah399a2922014-05-28 01:57:40 -0700826
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700827 // setupFullMesh();
Komal Shah399a2922014-05-28 01:57:40 -0700828
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700829 // Suppress link discovery on external-facing router ports
Komal Shah399a2922014-05-28 01:57:40 -0700830
831 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -0700832 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Komal Shah399a2922014-05-28 01:57:40 -0700833 }
834
835 bgpUpdatesExecutor.execute(new Runnable() {
836 @Override
837 public void run() {
838 doUpdatesThread();
839 }
840 });
841 }
842
Ray Milkey269ffb92014-04-03 14:43:30 -0700843 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700844 * Setup the Paths to the BGP Daemon. Run a loop for all of the bgpPeers
845 * Push flow from BGPd to the peer Push flow from peer to BGPd Parameters to
846 * pass to the intent are as follows: String id, long srcSwitch, long
847 * srcPort, long srcMac, int srcIP, long dstSwitch, long dstPort, long
848 * dstMac, int dstIP
Komal Shah399a2922014-05-28 01:57:40 -0700849 */
850 private void setupBgpPathsNew() {
851 IntentOperationList operations = new IntentOperationList();
852 for (BgpPeer bgpPeer : bgpPeers.values()) {
853 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700854 // Inet4Address.
Komal Shah399a2922014-05-28 01:57:40 -0700855 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
856 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700857 String fwdIntentId = caller + ":"
858 + controllerRegistryService.getNextUniqueId();
859 String bwdIntentId = caller + ":"
860 + controllerRegistryService.getNextUniqueId();
Komal Shah399a2922014-05-28 01:57:40 -0700861 SwitchPort srcPort =
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700862 new SwitchPort(bgpdAttachmentPoint.getDpid(),
863 bgpdAttachmentPoint.getPortNumber());
Komal Shah399a2922014-05-28 01:57:40 -0700864 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700865 new SwitchPort(new Dpid(peerInterface.getDpid()),
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700866 new PortNumber(peerInterface.getSwitchPort().getPortNumber()));
Komal Shah399a2922014-05-28 01:57:40 -0700867 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700868 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700869 ShortestPathIntent.EMPTYMACADDRESS, srcIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700870 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700871 ShortestPathIntent.EMPTYMACADDRESS, dstIP);
Komal Shah399a2922014-05-28 01:57:40 -0700872 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700873 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700874 ShortestPathIntent.EMPTYMACADDRESS, dstIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700875 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700876 ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700877 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
878 operations.add(operator, fwdIntent);
879 operations.add(operator, bwdIntent);
880 }
881 pathRuntime.executeIntentOperations(operations);
882 }
883
Ray Milkey269ffb92014-04-03 14:43:30 -0700884 @Override
885 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
886 log.debug("Received ARP response: {} => {}",
887 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700888
Ray Milkey269ffb92014-04-03 14:43:30 -0700889 /*
890 * We synchronize on this to prevent changes to the ptree while we're pushing
891 * flows to the switches. If the ptree changes, the ptree and switches
892 * could get out of sync.
893 */
894 synchronized (this) {
895 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700896
Ray Milkey269ffb92014-04-03 14:43:30 -0700897 if (path != null) {
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -0700898 log.debug("Pushing path to {} at {} on {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700899 path.getDstIpAddress().getHostAddress(), macAddress,
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -0700900 path.getDstInterface().getSwitchPort());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700901 // These paths should always be to BGP peers. Paths to non-peers
902 // are
Jonathan Hart938a0152014-04-07 18:27:31 -0700903 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -0700904 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700905 // A path already got pushed to this endpoint while we were
906 // waiting
907 // for ARP. We'll copy over the permanent attribute if it is
908 // set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -0700909 if (path.isPermanent()) {
910 pushedPaths.get(path.getDstIpAddress()).setPermanent();
911 }
912 } else {
913 calculateAndPushPath(path, macAddress);
914 pushedPaths.put(path.getDstIpAddress(), path);
915 }
916 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700917
Ray Milkey269ffb92014-04-03 14:43:30 -0700918 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700919
Ray Milkey269ffb92014-04-03 14:43:30 -0700920 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700921 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700922
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700923 RibEntry rib = bgpRoutes.getValueForExactKey(
924 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700925 if (rib != null && rib.equals(update.getRibEntry())) {
926 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
927 rib.getNextHop().getHostAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700928 // We only push prefix flows if the prefix is still in the
929 // ptree
930 // and the next hop is the same as our update. The prefix
931 // could
932 // have been removed while we were waiting for the ARP, or
933 // the
Jonathan Hart938a0152014-04-07 18:27:31 -0700934 // next hop could have changed.
Ray Milkey7531a342014-04-11 15:08:12 -0700935 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700936 } else {
937 log.debug("Received ARP response, but {},{} is no longer in ptree",
938 update.getPrefix(), update.getRibEntry());
939 }
940 }
941 }
942 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700943
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700944 // XXX OpenFlow message classes have been removed
945 /*private void setupArpFlows() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700946 OFMatch match = new OFMatch();
947 match.setDataLayerType(Ethernet.TYPE_ARP);
948 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700949
Ray Milkey269ffb92014-04-03 14:43:30 -0700950 OFFlowMod fm = new OFFlowMod();
951 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700952
Ray Milkey269ffb92014-04-03 14:43:30 -0700953 OFActionOutput action = new OFActionOutput();
954 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
955 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700956 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700957 actions.add(action);
958 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700959
Ray Milkey269ffb92014-04-03 14:43:30 -0700960 fm.setIdleTimeout((short) 0)
961 .setHardTimeout((short) 0)
962 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
963 .setCookie(0)
964 .setCommand(OFFlowMod.OFPFC_ADD)
965 .setPriority(ARP_PRIORITY)
966 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700967
Ray Milkey269ffb92014-04-03 14:43:30 -0700968 for (String strdpid : switches) {
969 flowCache.write(HexString.toLong(strdpid), fm);
970 }
971 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700972
Ray Milkey269ffb92014-04-03 14:43:30 -0700973 private void setupDefaultDropFlows() {
974 OFFlowMod fm = new OFFlowMod();
975 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -0700976 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700977
Ray Milkey269ffb92014-04-03 14:43:30 -0700978 fm.setIdleTimeout((short) 0)
979 .setHardTimeout((short) 0)
980 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
981 .setCookie(0)
982 .setCommand(OFFlowMod.OFPFC_ADD)
983 .setPriority((short) 0)
984 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700985
Ray Milkey269ffb92014-04-03 14:43:30 -0700986 OFFlowMod fmLLDP;
987 OFFlowMod fmBDDP;
988 try {
989 fmLLDP = fm.clone();
990 fmBDDP = fm.clone();
991 } catch (CloneNotSupportedException e1) {
992 log.error("Error cloning flow mod", e1);
993 return;
994 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700995
Ray Milkey269ffb92014-04-03 14:43:30 -0700996 OFMatch matchLLDP = new OFMatch();
997 matchLLDP.setDataLayerType((short) 0x88cc);
998 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
999 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001000
Ray Milkey269ffb92014-04-03 14:43:30 -07001001 OFMatch matchBDDP = new OFMatch();
1002 matchBDDP.setDataLayerType((short) 0x8942);
1003 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1004 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001005
Ray Milkey269ffb92014-04-03 14:43:30 -07001006 OFActionOutput action = new OFActionOutput();
1007 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1008 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001009 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -07001010 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001011
Ray Milkey269ffb92014-04-03 14:43:30 -07001012 fmLLDP.setActions(actions);
1013 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001014
Ray Milkey269ffb92014-04-03 14:43:30 -07001015 fmLLDP.setPriority(ARP_PRIORITY);
1016 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1017 fmBDDP.setPriority(ARP_PRIORITY);
1018 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001019
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001020 List<OFFlowMod> flowModList = new ArrayList<>(3);
Ray Milkey269ffb92014-04-03 14:43:30 -07001021 flowModList.add(fm);
1022 flowModList.add(fmLLDP);
1023 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001024
Ray Milkey269ffb92014-04-03 14:43:30 -07001025 for (String strdpid : switches) {
1026 flowCache.write(HexString.toLong(strdpid), flowModList);
1027 }
Jonathan Hartc78b8f62014-08-07 22:31:09 -07001028 }*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001029
Ray Milkey269ffb92014-04-03 14:43:30 -07001030 private void beginRouting() {
1031 log.debug("Topology is now ready, beginning routing function");
1032 // TODO: Fix for the new Topology Network Graph
1033 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001034
Ray Milkey269ffb92014-04-03 14:43:30 -07001035 // Wait Pavlin's API. We need the following functions.
1036 /*setupArpFlows();
1037 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001038
Jonathan Hart4de98c32014-08-11 17:03:25 -07001039 //setupBgpPaths();
Ray Milkey269ffb92014-04-03 14:43:30 -07001040 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001041
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001042 // Suppress link discovery on external-facing router ports
Ray Milkey269ffb92014-04-03 14:43:30 -07001043 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -07001044 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001045 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001046
Ray Milkey269ffb92014-04-03 14:43:30 -07001047 bgpUpdatesExecutor.execute(new Runnable() {
1048 @Override
1049 public void run() {
1050 doUpdatesThread();
1051 }
1052 });
1053 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001054
Jonathan Hart938a0152014-04-07 18:27:31 -07001055 // Before inserting the paths for BGP traffic, we should check whether
1056 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001057 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001058 // TODO: Fix the code below after topoSwitchSerice was removed
1059 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001060 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001061
Ray Milkey269ffb92014-04-03 14:43:30 -07001062 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1063 getActiveSwitches().iterator();
1064 while(activeSwitches.hasNext())
1065 {
1066 ISwitchObject switchObject = activeSwitches.next();
1067 if (switchObject.getDPID().equals(dpid)) {
1068 break;
1069 }
1070 if(activeSwitches.hasNext() == false) {
1071 log.debug("Not all switches are here yet");
1072 return;
1073 }
1074 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001075 }
1076 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001077 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001078 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001079
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001080 // Actually we only need to go half way round to verify full mesh
1081 // connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001082 private void checkTopologyReady() {
1083 for (Interface dstInterface : interfaces.values()) {
1084 for (Interface srcInterface : interfaces.values()) {
1085 if (dstInterface.equals(srcInterface)) {
1086 continue;
1087 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001088
Ray Milkey269ffb92014-04-03 14:43:30 -07001089 // TODO: Fix for the new Topology Network Graph
1090 /*
1091 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1092 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001093
Ray Milkey269ffb92014-04-03 14:43:30 -07001094 if (shortestPath == null){
1095 log.debug("Shortest path between {} and {} not found",
1096 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1097 return;
1098 }
1099 */
1100 }
1101 }
1102 topologyReady = true;
1103 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001104
Ray Milkey269ffb92014-04-03 14:43:30 -07001105 private void checkStatus() {
1106 if (!switchesConnected) {
1107 checkSwitchesConnected();
1108 }
1109 boolean oldTopologyReadyStatus = topologyReady;
1110 if (switchesConnected && !topologyReady) {
1111 checkTopologyReady();
1112 }
1113 if (!oldTopologyReadyStatus && topologyReady) {
1114 beginRouting();
1115 }
1116 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001117
Ray Milkey269ffb92014-04-03 14:43:30 -07001118 private void doUpdatesThread() {
1119 boolean interrupted = false;
1120 try {
1121 while (true) {
1122 try {
1123 RibUpdate update = ribUpdates.take();
1124 switch (update.getOperation()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001125 case UPDATE:
1126 if (validateUpdate(update)) {
1127 processRibAdd(update);
1128 } else {
1129 log.debug("Rib UPDATE out of order: {} via {}",
1130 update.getPrefix(), update.getRibEntry().getNextHop());
1131 }
1132 break;
1133 case DELETE:
1134 if (validateUpdate(update)) {
1135 processRibDelete(update);
1136 } else {
1137 log.debug("Rib DELETE out of order: {} via {}",
1138 update.getPrefix(), update.getRibEntry().getNextHop());
1139 }
1140 break;
1141 default:
1142 log.error("Unknown operation {}", update.getOperation());
1143 break;
Ray Milkey269ffb92014-04-03 14:43:30 -07001144 }
1145 } catch (InterruptedException e) {
1146 log.debug("Interrupted while taking from updates queue", e);
1147 interrupted = true;
1148 } catch (Exception e) {
1149 log.debug("exception", e);
1150 }
1151 }
1152 } finally {
1153 if (interrupted) {
1154 Thread.currentThread().interrupt();
1155 }
1156 }
1157 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001158
Ray Milkey269ffb92014-04-03 14:43:30 -07001159 private boolean validateUpdate(RibUpdate update) {
1160 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001161 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
1162 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001163
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001164 // If there is no existing entry we must assume this is the most recent
1165 // update. However this might not always be the case as we might have a
1166 // POST then DELETE reordering.
1167 // if (oldEntry == null ||
1168 // !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001169 if (oldEntry == null) {
1170 return true;
1171 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001172
Ray Milkey269ffb92014-04-03 14:43:30 -07001173 // This handles the case where routes are gathered in the initial
1174 // request because they don't have sequence number info
1175 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1176 return true;
1177 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001178
Ray Milkey269ffb92014-04-03 14:43:30 -07001179 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1180 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001181 }
Ray Milkey4985f212014-04-10 16:57:05 -07001182
1183 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001184 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -07001185 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001186
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001187 private Interface longestInterfacePrefixMatch(InetAddress address) {
1188 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
1189 Prefix.MAX_PREFIX_LENGTH);
1190 Iterator<Interface> it =
1191 interfaceRoutes.getValuesForKeysPrefixing(
1192 prefixToSearchFor.toBinaryString()).iterator();
1193 Interface intf = null;
1194 // Find the last prefix, which will be the longest prefix
1195 while (it.hasNext()) {
1196 intf = it.next();
1197 }
1198
1199 return intf;
1200 }
1201
Ray Milkey269ffb92014-04-03 14:43:30 -07001202 // The code below should be reimplemented after removal of Floodlight's
1203 // ITopologyService API. It should be implemented on top of network graph
1204 // notifications. (It was pretty hacky anyway...)
1205 /*
1206 @Override
1207 public void topologyChanged() {
1208 if (topologyReady) {
1209 return;
1210 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001211
Ray Milkey269ffb92014-04-03 14:43:30 -07001212 boolean refreshNeeded = false;
1213 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1214 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1215 //We don't need to recalculate anything for just link updates
1216 //They happen very frequently
1217 refreshNeeded = true;
1218 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001219
Ray Milkey269ffb92014-04-03 14:43:30 -07001220 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001221
Ray Milkey269ffb92014-04-03 14:43:30 -07001222 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1223 synchronized (linkUpdates) {
1224 linkUpdates.add(ldu);
1225 }
1226 }
1227 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001228
Ray Milkey269ffb92014-04-03 14:43:30 -07001229 if (refreshNeeded && !topologyReady){
1230 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1231 }
1232 }
1233 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001234
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001235 // ******************
1236 // IOFSwitchListener
1237 // ******************
1238
Ray Milkey269ffb92014-04-03 14:43:30 -07001239 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001240 public void switchActivatedMaster(long swId) {
1241 IOFSwitch sw = floodlightProvider.getSwitch(swId);
1242 if (sw == null) {
1243 log.warn("Added switch not available {} ", swId);
1244 return;
1245 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001246 if (!topologyReady) {
1247 sw.clearAllFlowMods();
1248 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001249
Jonathan Hartc78b8f62014-08-07 22:31:09 -07001250 //flowCache.switchConnected(sw);
Ray Milkey269ffb92014-04-03 14:43:30 -07001251 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001252
Ray Milkey269ffb92014-04-03 14:43:30 -07001253 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001254 public void switchActivatedEqual(long swId) {
1255 // TODO Auto-generated method stub
1256
1257 }
1258
1259 @Override
1260 public void switchMasterToEqual(long swId) {
1261 // TODO Auto-generated method stub
1262
1263 }
1264
1265 @Override
1266 public void switchEqualToMaster(long swId) {
1267 // for now treat as switchActivatedMaster
1268 switchActivatedMaster(swId);
1269 }
1270
1271 @Override
1272 public void switchDisconnected(long swId) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001273 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001274 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001275
Ray Milkey269ffb92014-04-03 14:43:30 -07001276 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001277 public void switchPortChanged(long swId, OFPortDesc port, PortChangeType pct) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001278 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001279 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001280
Ray Milkey269ffb92014-04-03 14:43:30 -07001281 @Override
1282 public String getName() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001283 return "sdnip";
Ray Milkey269ffb92014-04-03 14:43:30 -07001284 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001285
Ray Milkey269ffb92014-04-03 14:43:30 -07001286 /*
1287 * IConfigInfoService methods
1288 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001289
Ray Milkey269ffb92014-04-03 14:43:30 -07001290 @Override
1291 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001292 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001293 return (intf != null && intf.getIpAddress().equals(address));
1294 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001295
Ray Milkey269ffb92014-04-03 14:43:30 -07001296 @Override
1297 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001298 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001299 return (intf != null && !intf.getIpAddress().equals(address));
1300 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001301
Ray Milkey269ffb92014-04-03 14:43:30 -07001302 @Override
1303 public boolean fromExternalNetwork(long inDpid, short inPort) {
1304 for (Interface intf : interfaces.values()) {
1305 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1306 return true;
1307 }
1308 }
1309 return false;
1310 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001311
Ray Milkey269ffb92014-04-03 14:43:30 -07001312 @Override
1313 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001314 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -07001315 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001316
Ray Milkey269ffb92014-04-03 14:43:30 -07001317 @Override
1318 public boolean hasLayer3Configuration() {
1319 return !interfaces.isEmpty();
1320 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001321
Ray Milkey269ffb92014-04-03 14:43:30 -07001322 @Override
1323 public MACAddress getRouterMacAddress() {
1324 return bgpdMacAddress;
1325 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001326
Ray Milkey269ffb92014-04-03 14:43:30 -07001327 @Override
1328 public short getVlan() {
1329 return vlan;
1330 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001331}