blob: 135d0a73181c7d2250af6657d166b8e23991826a [file] [log] [blame]
Jonathan Hart8f6dc092014-04-18 15:56:43 -07001package net.onrc.onos.apps.sdnip;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
Jonathan Hartd1f23252013-06-13 15:17:05 +12003import java.io.File;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07004import java.io.IOException;
5import java.net.InetAddress;
pingping-lina2cbfad2013-03-07 08:39:21 +08006import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07007import java.util.Collection;
pingping-lina2cbfad2013-03-07 08:39:21 +08008import java.util.HashMap;
Jonathan Hartf6978ce2014-06-23 11:20:04 -07009import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070010import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070011import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120012import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120013import java.util.concurrent.BlockingQueue;
14import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120015import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120016import java.util.concurrent.LinkedBlockingQueue;
pingping-lina2cbfad2013-03-07 08:39:21 +080017
Jonathan Hart61ba9372013-05-19 20:10:29 -070018import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070019import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070020import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
Jonathan Hart64c0b202013-08-20 15:45:07 +120021import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080022import net.floodlightcontroller.core.module.FloodlightModuleContext;
23import net.floodlightcontroller.core.module.FloodlightModuleException;
24import net.floodlightcontroller.core.module.IFloodlightModule;
25import net.floodlightcontroller.core.module.IFloodlightService;
pingping-lina2cbfad2013-03-07 08:39:21 +080026import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120027import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0961fe82014-04-03 09:56:25 -070028import net.onrc.onos.apps.proxyarp.IArpRequester;
29import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart8f6dc092014-04-18 15:56:43 -070030import net.onrc.onos.apps.sdnip.RibUpdate.Operation;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070031import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutable;
Komal Shah399a2922014-05-28 01:57:40 -070032import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutableNew;
33import net.onrc.onos.core.intent.IntentOperation;
34import net.onrc.onos.core.intent.IntentOperationList;
35import net.onrc.onos.core.intent.ShortestPathIntent;
36import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
Jonathan Harta99ec672014-04-03 11:30:34 -070037import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070038import net.onrc.onos.core.main.config.IConfigInfoService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070039import net.onrc.onos.core.packet.Ethernet;
40import net.onrc.onos.core.packet.IPv4;
Komal Shah399a2922014-05-28 01:57:40 -070041import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart23701d12014-04-03 10:45:48 -070042import net.onrc.onos.core.util.CallerId;
43import net.onrc.onos.core.util.DataPath;
44import net.onrc.onos.core.util.Dpid;
45import net.onrc.onos.core.util.FlowEntryAction;
46import net.onrc.onos.core.util.FlowEntryActions;
47import net.onrc.onos.core.util.FlowEntryMatch;
48import net.onrc.onos.core.util.FlowId;
49import net.onrc.onos.core.util.FlowPath;
50import net.onrc.onos.core.util.FlowPathFlags;
51import net.onrc.onos.core.util.FlowPathType;
52import net.onrc.onos.core.util.FlowPathUserState;
53import net.onrc.onos.core.util.IPv4Net;
Yuta HIGUCHIfb564502014-06-16 21:29:00 -070054import net.onrc.onos.core.util.PortNumber;
Jonathan Hart23701d12014-04-03 10:45:48 -070055import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080056import net.sf.json.JSONArray;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070057import net.sf.json.JSONException;
pingping-line2a09ca2013-03-23 09:33:58 +080058import net.sf.json.JSONObject;
59import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080060
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070061import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120062import org.codehaus.jackson.JsonParseException;
63import org.codehaus.jackson.map.JsonMappingException;
64import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070065import org.openflow.protocol.OFFlowMod;
66import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070067import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120068import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070069import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070070import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120071import org.openflow.util.HexString;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070072import org.projectfloodlight.openflow.protocol.OFPortDesc;
pingping-lina2cbfad2013-03-07 08:39:21 +080073import org.slf4j.Logger;
74import org.slf4j.LoggerFactory;
75
Jonathan Hart4dfc3652013-08-02 20:22:36 +120076import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120077import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120078import com.google.common.collect.Multimaps;
79import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120080import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120081import com.google.common.util.concurrent.ThreadFactoryBuilder;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070082import com.googlecode.concurrenttrees.radix.RadixTree;
83import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
84import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
85import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120086
Jonathan Hart8f6dc092014-04-18 15:56:43 -070087public class SdnIp implements IFloodlightModule, ISdnIpService,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070088 IArpRequester, IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070089
Jonathan Hart8f6dc092014-04-18 15:56:43 -070090 private static final Logger log = LoggerFactory.getLogger(SdnIp.class);
Sho SHIMIZU9ec39822014-07-10 17:15:12 -070091 private final CallerId callerId = new CallerId("SDNIP");
pingping-lina2cbfad2013-03-07 08:39:21 +080092
Ray Milkey269ffb92014-04-03 14:43:30 -070093 private IFloodlightProviderService floodlightProvider;
94 private ILinkDiscoveryService linkDiscoveryService;
95 private IRestApiService restApi;
96 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070097
Jonathan Hartf6978ce2014-06-23 11:20:04 -070098 private InvertedRadixTree<RibEntry> bgpRoutes;
99 private InvertedRadixTree<Interface> interfaceRoutes;
100
Ray Milkey269ffb92014-04-03 14:43:30 -0700101 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700102
Ray Milkey269ffb92014-04-03 14:43:30 -0700103 private String bgpdRestIp;
104 private String routerId;
Ray Milkey5df613b2014-04-15 10:50:56 -0700105 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
106 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700107
Komal Shah399a2922014-05-28 01:57:40 -0700108 /* ShortestPath Intent Variables */
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700109 private final String caller = "SdnIp";
Komal Shah399a2922014-05-28 01:57:40 -0700110 private IControllerRegistryService controllerRegistryService;
111 private IPathCalcRuntimeService pathRuntime;
112 /* Shortest Intent Path Variables */
113
Ray Milkey2476cac2014-04-08 11:03:21 -0700114 private static final short ARP_PRIORITY = 20;
Ray Milkey5d406012014-04-08 14:44:41 -0700115
Jonathan Hart938a0152014-04-07 18:27:31 -0700116 // The fields below are unused after the move to FlowManager.
117 // Remove them if no longer needed.
118 /*
119 // We need to identify our flows somehow, in lieu of an OS-wide mechanism
120 // to hand out cookie IDs to prevent conflicts.
121 private static final long APP_COOKIE = 0xa0000000000000L;
122 // Cookie for flows that do L2 forwarding within SDN domain to egress routers
123 private static final long L2_FWD_COOKIE = APP_COOKIE + 1;
124 // Cookie for flows in ingress switches that rewrite the MAC address
125 private static final long MAC_RW_COOKIE = APP_COOKIE + 2;
126 // Cookie for flows that setup BGP paths
127 private static final long BGP_COOKIE = APP_COOKIE + 3;
128 // Forwarding uses priority 0, and the mac rewrite entries in ingress switches
129 // need to be higher priority than this otherwise the rewrite may not get done
130 private static final short SDNIP_PRIORITY = 10;
131 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700132
Ray Milkey2476cac2014-04-08 11:03:21 -0700133 private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700134
Jonathan Hart938a0152014-04-07 18:27:31 -0700135 private static final int TOPO_DETECTION_WAIT = 2; // seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700136
Jonathan Hart938a0152014-04-07 18:27:31 -0700137 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700138 private List<String> switches;
139 private Map<String, Interface> interfaces;
140 private Map<InetAddress, BgpPeer> bgpPeers;
141 private SwitchPort bgpdAttachmentPoint;
142 private MACAddress bgpdMacAddress;
143 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700144
Jonathan Hart938a0152014-04-07 18:27:31 -0700145 // True when all switches have connected
Ray Milkey269ffb92014-04-03 14:43:30 -0700146 private volatile boolean switchesConnected = false;
Jonathan Hart938a0152014-04-07 18:27:31 -0700147 // True when we have a full mesh of shortest paths between gateways
Ray Milkey269ffb92014-04-03 14:43:30 -0700148 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200149
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700150 // private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700151
Ray Milkey269ffb92014-04-03 14:43:30 -0700152 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700153
Ray Milkey269ffb92014-04-03 14:43:30 -0700154 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700155
Ray Milkey269ffb92014-04-03 14:43:30 -0700156 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700157
Ray Milkey269ffb92014-04-03 14:43:30 -0700158 private Map<InetAddress, Path> pushedPaths;
159 private Map<Prefix, Path> prefixToPath;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700160 // private Multimap<Prefix, PushedFlowMod> pushedFlows;
Ray Milkey269ffb92014-04-03 14:43:30 -0700161 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700162
Ray Milkey269ffb92014-04-03 14:43:30 -0700163 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700164
Ray Milkey269ffb92014-04-03 14:43:30 -0700165 // TODO: Fix for the new Topology Network Graph
166 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700167
Jonathan Hart284e70f2014-07-05 12:32:51 -0700168 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700169 private class TopologyChangeDetector implements Runnable {
170 @Override
171 public void run() {
172 log.debug("Running topology change detection task");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700173 // TODO: Fix the code below after topoLinkService was removed
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 synchronized (linkUpdates) {
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700175
Ray Milkey269ffb92014-04-03 14:43:30 -0700176 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700177
Ray Milkey269ffb92014-04-03 14:43:30 -0700178 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700179
Ray Milkey269ffb92014-04-03 14:43:30 -0700180 Iterator<LDUpdate> it = linkUpdates.iterator();
181 while (it.hasNext()){
182 LDUpdate ldu = it.next();
183 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
184 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700185
Ray Milkey269ffb92014-04-03 14:43:30 -0700186 if (activeLinks.contains(l)){
187 it.remove();
188 }
189 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700190 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700191
Ray Milkey269ffb92014-04-03 14:43:30 -0700192 if (!topologyReady) {
193 if (linkUpdates.isEmpty()) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700194 // All updates have been seen in network map.
195 // We can check if topology is ready
Ray Milkey269ffb92014-04-03 14:43:30 -0700196 log.debug("No known changes outstanding. Checking topology now");
197 checkStatus();
198 } else {
Jonathan Hart938a0152014-04-07 18:27:31 -0700199 // We know of some link updates that haven't propagated to the database yet
Ray Milkey269ffb92014-04-03 14:43:30 -0700200 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
201 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
202 }
203 }
204 }
205 }
Jonathan Hart284e70f2014-07-05 12:32:51 -0700206 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700207
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 private void readConfiguration(String configFilename) {
209 File gatewaysFile = new File(configFilename);
210 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700211
Ray Milkey269ffb92014-04-03 14:43:30 -0700212 try {
213 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700214
Ray Milkey269ffb92014-04-03 14:43:30 -0700215 switches = config.getSwitches();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700216 interfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700217 for (Interface intf : config.getInterfaces()) {
218 interfaces.put(intf.getName(), intf);
219 }
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700220 bgpPeers = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700221 for (BgpPeer peer : config.getPeers()) {
222 bgpPeers.put(peer.getIpAddress(), peer);
223 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700224
Ray Milkey269ffb92014-04-03 14:43:30 -0700225 bgpdAttachmentPoint = new SwitchPort(
226 new Dpid(config.getBgpdAttachmentDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700227 new PortNumber(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700228
Ray Milkey269ffb92014-04-03 14:43:30 -0700229 bgpdMacAddress = config.getBgpdMacAddress();
230 vlan = config.getVlan();
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -0700231 } catch (JsonParseException | JsonMappingException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700233 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700234 } catch (IOException e) {
235 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700236 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700237 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700238
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700239 // Populate the interface Patricia Tree
Ray Milkey269ffb92014-04-03 14:43:30 -0700240 for (Interface intf : interfaces.values()) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700241 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
242 intf.getPrefixLength());
243 interfaceRoutes.put(prefix.toBinaryString(), intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700244 }
245 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700246
Ray Milkey269ffb92014-04-03 14:43:30 -0700247 @Override
248 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700249 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700250 l.add(ISdnIpService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700251 l.add(IConfigInfoService.class);
252 return l;
253 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700254
Ray Milkey269ffb92014-04-03 14:43:30 -0700255 @Override
256 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700257 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700258 m.put(ISdnIpService.class, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700259 m.put(IConfigInfoService.class, this);
260 return m;
261 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800262
Ray Milkey269ffb92014-04-03 14:43:30 -0700263 @Override
264 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700265 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700266 l.add(IFloodlightProviderService.class);
267 l.add(IRestApiService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700268 l.add(IControllerRegistryService.class);
269 l.add(IPathCalcRuntimeService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700270 return l;
271 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700272
Ray Milkey269ffb92014-04-03 14:43:30 -0700273 @Override
274 public void init(FloodlightModuleContext context)
275 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700276
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700277 bgpRoutes = new ConcurrentInvertedRadixTree<>(
278 new DefaultByteArrayNodeFactory());
279 interfaceRoutes = new ConcurrentInvertedRadixTree<>(
280 new DefaultByteArrayNodeFactory());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700281
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700282 ribUpdates = new LinkedBlockingQueue<>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700283
Ray Milkey269ffb92014-04-03 14:43:30 -0700284 // Register floodlight provider and REST handler.
285 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
286 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
287 restApi = context.getServiceImpl(IRestApiService.class);
288 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800289
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700290 controllerRegistryService = context
291 .getServiceImpl(IControllerRegistryService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700292 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700293
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700294 // ScheduledExecutorService executor =
295 // Executors.newScheduledThreadPool(1);
296 // topologyChangeDetectorTask = new SingletonTask(executor, new
297 // TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700298
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700299 pathsWaitingOnArp = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700300 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
301 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700302
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700303 pushedPaths = new HashMap<>();
304 prefixToPath = new HashMap<>();
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700305 // pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700306 pushedFlowIds = HashMultimap.create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700307
Ray Milkey269ffb92014-04-03 14:43:30 -0700308 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700309
Ray Milkey269ffb92014-04-03 14:43:30 -0700310 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
311 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700312
Jonathan Hart938a0152014-04-07 18:27:31 -0700313 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700314 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
315 if (bgpdRestIp == null) {
316 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700317 throw new ConfigurationRuntimeException(
318 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700319 } else {
320 log.info("BgpdRestIp set to {}", bgpdRestIp);
321 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700322
Ray Milkey269ffb92014-04-03 14:43:30 -0700323 routerId = context.getConfigParams(this).get("RouterId");
324 if (routerId == null) {
325 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700326 throw new ConfigurationRuntimeException(
327 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700328 } else {
329 log.info("RouterId set to {}", routerId);
330 }
pingping-linba5c52f2014-02-11 16:52:01 -0800331
Ray Milkey269ffb92014-04-03 14:43:30 -0700332 String configFilenameParameter = context.getConfigParams(this).get("configfile");
333 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700334 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700335 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700336 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700337
Ray Milkey5df613b2014-04-15 10:50:56 -0700338 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700339 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700340
Ray Milkey269ffb92014-04-03 14:43:30 -0700341 @Override
342 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700343 restApi.addRestletRoutable(new SdnIpWebRoutable());
Komal Shah399a2922014-05-28 01:57:40 -0700344 restApi.addRestletRoutable(new SdnIpWebRoutableNew());
Ray Milkey269ffb92014-04-03 14:43:30 -0700345 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800346
Jonathan Hart938a0152014-04-07 18:27:31 -0700347 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700348 retrieveRib();
349 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800350
Ray Milkey269ffb92014-04-03 14:43:30 -0700351 @Override
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700352 public RadixTree<RibEntry> getPtree() {
353 return bgpRoutes;
Ray Milkey269ffb92014-04-03 14:43:30 -0700354 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700355
Ray Milkey269ffb92014-04-03 14:43:30 -0700356 @Override
357 public void clearPtree() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700358 log.warn("Clear table operation not supported");
Ray Milkey269ffb92014-04-03 14:43:30 -0700359 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700360
Ray Milkey269ffb92014-04-03 14:43:30 -0700361 @Override
Jonathan Hart31e15f12014-04-10 10:33:00 -0700362 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700363 return bgpdRestIp;
364 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700365
Ray Milkey269ffb92014-04-03 14:43:30 -0700366 @Override
367 public String getRouterId() {
368 return routerId;
369 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700370
Ray Milkey269ffb92014-04-03 14:43:30 -0700371 private void retrieveRib() {
372 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
373 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700374
Jonathan Hart938a0152014-04-07 18:27:31 -0700375 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700376 return;
377 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700378
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700379 try {
380 response = response.replaceAll("\"", "'");
381 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
382 JSONArray ribArray = jsonObj.getJSONArray("rib");
383 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700384
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700385 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700386
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700387 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700388
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700389 for (int j = 0; j < size; j++) {
390 JSONObject ribEntry = ribArray.getJSONObject(j);
391 String prefix = ribEntry.getString("prefix");
392 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700393
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700394 // Insert each rib entry into the local rib
395 String[] substring = prefix.split("/");
396 String prefix1 = substring[0];
397 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700398
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700399 Prefix p;
400 try {
401 p = new Prefix(prefix1, Integer.parseInt(mask1));
402 } catch (NumberFormatException e) {
403 log.warn("Wrong mask format in RIB JSON: {}", mask1);
404 continue;
405 } catch (IllegalArgumentException e1) {
406 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
407 continue;
408 }
409
410 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
411
412 try {
413 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
414 } catch (InterruptedException e) {
415 log.debug("Interrupted while pushing onto update queue");
416 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700417 }
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700418 } catch (JSONException e) {
419 // TODO don't parse JSON manually
420 log.error("Error parsing inital route table JSON:", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700421 }
422 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700423
Ray Milkey269ffb92014-04-03 14:43:30 -0700424 @Override
425 public void newRibUpdate(RibUpdate update) {
426 try {
427 ribUpdates.put(update);
428 } catch (InterruptedException e) {
429 log.debug("Interrupted while putting on ribUpdates queue", e);
430 Thread.currentThread().interrupt();
431 }
432 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700433
Sho SHIMIZUba372192014-07-10 08:59:57 -0700434 private void processRibAdd(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700435 synchronized (this) {
436 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700437
Jonathan Hart938a0152014-04-07 18:27:31 -0700438 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700439
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700440 RibEntry rib = bgpRoutes.put(prefix.toBinaryString(), update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700441
Jonathan Hart938a0152014-04-07 18:27:31 -0700442 if (rib != null && !rib.equals(update.getRibEntry())) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700443 // There was an existing nexthop for this prefix. This update
444 // supersedes that,
445 // so we need to remove the old flows for this prefix from the
446 // switches
Ray Milkey7531a342014-04-11 15:08:12 -0700447 executeDeletePrefix(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700448 }
Ray Milkey5d406012014-04-08 14:44:41 -0700449
Jonathan Hart938a0152014-04-07 18:27:31 -0700450 if (update.getRibEntry().getNextHop().equals(
451 InetAddresses.forString("0.0.0.0"))) {
452 // Route originated by SDN domain
453 // We don't handle these at the moment
454 log.debug("Own route {} to {}", prefix,
455 update.getRibEntry().getNextHop().getHostAddress());
456 return;
457 }
Ray Milkey5d406012014-04-08 14:44:41 -0700458
Ray Milkey7531a342014-04-11 15:08:12 -0700459 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700460 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700461 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700462
Ray Milkey7531a342014-04-11 15:08:12 -0700463 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700464 // TODO: Fix the code below. Note that "deviceStorage" was removed.
465
466 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700467 Prefix prefix = update.getPrefix();
468 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700469
Ray Milkey269ffb92014-04-03 14:43:30 -0700470 InetAddress dstIpAddress = rib.getNextHop();
471 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800472
Ray Milkey269ffb92014-04-03 14:43:30 -0700473 // See if we know the MAC address of the next hop
474 // 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 -0700475 IDeviceObject nextHopDevice =
476 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700477
Ray Milkey269ffb92014-04-03 14:43:30 -0700478 if (nextHopDevice == null){
479 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
480 prefixesWaitingOnArp.put(dstIpAddress,
481 new RibUpdate(Operation.UPDATE, prefix, rib));
482 proxyArp.sendArpRequest(dstIpAddress, this, true);
483 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800484
Ray Milkey269ffb92014-04-03 14:43:30 -0700485 }
486 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700487
Ray Milkey269ffb92014-04-03 14:43:30 -0700488 // Find the attachment point (egress interface) of the next hop
489 Interface egressInterface = null;
490 if (bgpPeers.containsKey(dstIpAddress)) {
491 //Route to a peer
492 log.debug("Route to peer {}", dstIpAddress);
493 BgpPeer peer = bgpPeers.get(dstIpAddress);
494 egressInterface = interfaces.get(peer.getInterfaceName());
495 } else {
496 //Route to non-peer
497 log.debug("Route to non-peer {}", dstIpAddress);
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700498 egressInterface = interfacePtree.match(
Ray Milkey269ffb92014-04-03 14:43:30 -0700499 new Prefix(dstIpAddress.getAddress(), 32));
500 if (egressInterface == null) {
501 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
502 return;
503 }
504 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700505
Ray Milkey269ffb92014-04-03 14:43:30 -0700506 if (nextHopMacAddress == null) {
507 prefixesWaitingOnArp.put(dstIpAddress,
508 new RibUpdate(Operation.UPDATE, prefix, rib));
509 proxyArp.sendArpRequest(dstIpAddress, this, true);
510 return;
511 } else {
512 if (!bgpPeers.containsKey(dstIpAddress)) {
513 //If the prefix is for a non-peer we need to ensure there's a path,
514 //and push one if there isn't.
515 Path path = pushedPaths.get(dstIpAddress);
516 if (path == null) {
517 path = new Path(egressInterface, dstIpAddress);
518 calculateAndPushPath(path, nextHopMacAddress);
519 pushedPaths.put(dstIpAddress, path);
520 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700521
Ray Milkey269ffb92014-04-03 14:43:30 -0700522 path.incrementUsers();
523 prefixToPath.put(prefix, path);
524 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700525
Ray Milkey269ffb92014-04-03 14:43:30 -0700526 //For all prefixes we need to add the first-hop mac-rewriting flows
527 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
528 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700529 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700530 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700531
Ray Milkey269ffb92014-04-03 14:43:30 -0700532 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700533 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix to
534 * all other border switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700535 */
536 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700537 MACAddress nextHopMacAddress) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700538 log.debug("Adding flows for prefix {}, next hop mac {}",
539 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700540
Ray Milkey269ffb92014-04-03 14:43:30 -0700541 FlowPath flowPath = new FlowPath();
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700542 flowPath.setInstallerId(callerId);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700543
Ray Milkey269ffb92014-04-03 14:43:30 -0700544 // Set flowPath FlowPathType and FlowPathUserState
545 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
546 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800547
Ray Milkey269ffb92014-04-03 14:43:30 -0700548 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
549 // only to the first-host switches
550 FlowPathFlags flowPathFlags = new FlowPathFlags();
551 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
552 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800553
Ray Milkey269ffb92014-04-03 14:43:30 -0700554 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700555 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700556 new SwitchPort(new Dpid(egressInterface.getDpid()),
557 new PortNumber(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800558
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700559 // We only need one flow mod per switch, so pick one interface on each
560 // switch
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700561 Map<Long, Interface> srcInterfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700562 for (Interface intf : interfaces.values()) {
563 if (!srcInterfaces.containsKey(intf.getDpid())
564 && !intf.equals(egressInterface)) {
565 srcInterfaces.put(intf.getDpid(), intf);
566 }
567 }
568 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800569
Ray Milkey269ffb92014-04-03 14:43:30 -0700570 if (egressInterface.equals(srcInterface)) {
571 continue;
572 }
pingping-linba5c52f2014-02-11 16:52:01 -0800573
Ray Milkey269ffb92014-04-03 14:43:30 -0700574 // Create flowPath FlowId
575 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800576
Ray Milkey269ffb92014-04-03 14:43:30 -0700577 // Create DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700578 SwitchPort srcPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700579 new SwitchPort(new Dpid(srcInterface.getDpid()),
580 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800581
Ray Milkey269ffb92014-04-03 14:43:30 -0700582 DataPath dataPath = new DataPath();
583 dataPath.setSrcPort(srcPort);
584 dataPath.setDstPort(dstPort);
585 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800586
Ray Milkey269ffb92014-04-03 14:43:30 -0700587 // Create flow path matching condition(s): IPv4 Prefix
588 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700589 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700590 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
591 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
592 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300593
Ray Milkey269ffb92014-04-03 14:43:30 -0700594 /*
595 * Create the Flow Entry Action(s): dst-MAC rewrite action
596 */
597 FlowEntryActions flowEntryActions = new FlowEntryActions();
598 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
599 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
600 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
601 flowEntryActions.addAction(flowEntryAction1);
602 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800603
Ray Milkey269ffb92014-04-03 14:43:30 -0700604 // Flow Path installation, only to first hop switches
605 // TODO: Add the flow by using the new Path Intent framework
606 /*
607 if (flowManagerService.addFlow(flowPath) == null) {
608 log.error("Failed to install flow path to the first hop for " +
609 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
610 nextHopMacAddress);
611 }
612 else {
613 log.debug("Successfully installed flow path to the first hop " +
614 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
615 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800616
Ray Milkey269ffb92014-04-03 14:43:30 -0700617 pushedFlowIds.put(prefix, flowPath.flowId());
618 }
619 */
620 }
621 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700622
Sho SHIMIZUba372192014-07-10 08:59:57 -0700623 private void processRibDelete(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700624 synchronized (this) {
625 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700626
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700627 // if (ptree.remove(prefix, update.getRibEntry())) {
628 // TODO check the change of logic here - remove doesn't check that
629 // the
630 // rib entry was what we expected (and we can't do this
631 // concurrently)
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700632 if (bgpRoutes.remove(prefix.toBinaryString())) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700633 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700634 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700635 * If no entry was removed, the <prefix, nexthop> wasn't there so
636 * it's probably already been removed and we don't need to do anything
637 */
Ray Milkey7531a342014-04-11 15:08:12 -0700638 executeDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart938a0152014-04-07 18:27:31 -0700639 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700640 }
641 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700642
Ray Milkey7531a342014-04-11 15:08:12 -0700643 private void executeDeletePrefix(Prefix prefix, RibEntry ribEntry) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700644 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700645
Ray Milkey269ffb92014-04-03 14:43:30 -0700646 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700647
Ray Milkey269ffb92014-04-03 14:43:30 -0700648 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
649 log.debug("Getting path for route with non-peer nexthop");
650 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700651
Ray Milkey269ffb92014-04-03 14:43:30 -0700652 if (path != null) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700653 // path could be null if we added to the Ptree but didn't push
654 // flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700655
Ray Milkey269ffb92014-04-03 14:43:30 -0700656 path.decrementUsers();
657 if (path.getUsers() <= 0 && !path.isPermanent()) {
658 deletePath(path);
659 pushedPaths.remove(path.getDstIpAddress());
660 }
661 }
662 }
663 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700664
Ray Milkey269ffb92014-04-03 14:43:30 -0700665 // TODO have not tested this module
666 private void deletePrefixFlows(Prefix prefix) {
667 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700668
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700669 //
670 // TODO: Delete the flow by using the new Path Intent framework
671 // NOTE: During the refactoring of the code below, if obtaining
672 // the values of the removed flowIds is needed, the first
673 // removeAll() statement should be replaced with the second removeAll()
674 // statement.
675 //
676 pushedFlowIds.removeAll(prefix);
677 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700678 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
679 for (FlowId flowId : flowIds) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700680 if (log.isTraceEnabled()) {
681 //Trace the flow status by flowPath in the switch before deleting it
682 log.trace("Pushing a DELETE flow mod to flowPath : {}",
683 flowManagerService.getFlow(flowId).toString());
684 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700685
Ray Milkey269ffb92014-04-03 14:43:30 -0700686 if( flowManagerService.deleteFlow(flowId))
687 {
688 log.debug("Successfully deleted FlowId: {}",flowId);
689 }
690 else
691 {
692 log.debug("Failed to delete FlowId: {}",flowId);
693 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700694 }
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700695 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700696 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700697
Ray Milkey269ffb92014-04-03 14:43:30 -0700698 // TODO need to record the path and then delete here
699 private void deletePath(Path path) {
700 log.debug("Deleting flows for path to {}",
701 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700702
Ray Milkey269ffb92014-04-03 14:43:30 -0700703 // TODO need update
704 /*for (PushedFlowMod pfm : path.getFlowMods()) {
705 if (log.isTraceEnabled()) {
706 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
707 new Object[] {HexString.toHexString(pfm.getDpid()),
708 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
709 });
710 }
pingping-linba5c52f2014-02-11 16:52:01 -0800711
Ray Milkey269ffb92014-04-03 14:43:30 -0700712 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
713 }*/
714 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700715
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700716 // TODO test next-hop changes
717 // TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800718
Ray Milkey269ffb92014-04-03 14:43:30 -0700719 /**
720 * On startup, we need to calculate a full mesh of paths between all gateway
Ray Milkeyb41100a2014-04-10 10:42:15 -0700721 * switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700722 */
723 private void setupFullMesh() {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700724 // TODO: Fix the code below. Note that "deviceStorage" was removed.
725
726 /*
727
Ray Milkey269ffb92014-04-03 14:43:30 -0700728 //For each border router, calculate and install a path from every other
729 //border switch to said border router. However, don't install the entry
730 //in to the first hop switch, as we need to install an entry to rewrite
731 //for each prefix received. This will be done later when prefixes have
732 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700733
Ray Milkey269ffb92014-04-03 14:43:30 -0700734 for (BgpPeer peer : bgpPeers.values()) {
735 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700736
Ray Milkey269ffb92014-04-03 14:43:30 -0700737 //We know there's not already a Path here pushed, because this is
738 //called before all other routing
739 Path path = new Path(peerInterface, peer.getIpAddress());
740 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700741
Ray Milkey269ffb92014-04-03 14:43:30 -0700742 //See if we know the MAC address of the peer. If not we can't
743 //do anything until we learn it
Ray Milkey269ffb92014-04-03 14:43:30 -0700744 MACAddress macAddress = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700745 IDeviceObject nextHopDevice =
746 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800747
Ray Milkey269ffb92014-04-03 14:43:30 -0700748 if(nextHopDevice == null){
749 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
750 //Put in the pending paths list first
751 pathsWaitingOnArp.put(peer.getIpAddress(), path);
752 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
753 continue;
754 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700755
Ray Milkey269ffb92014-04-03 14:43:30 -0700756 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
pingping-linba5c52f2014-02-11 16:52:01 -0800757
Ray Milkey269ffb92014-04-03 14:43:30 -0700758 if (macAddress == null) {
759 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
760 //Put in the pending paths list first
761 pathsWaitingOnArp.put(peer.getIpAddress(), path);
762 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
763 continue;
764 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700765
Ray Milkey269ffb92014-04-03 14:43:30 -0700766 //If we know the MAC, lets go ahead and push the paths to this peer
767 calculateAndPushPath(path, macAddress);
768 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700769 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700770 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700771
Ray Milkey269ffb92014-04-03 14:43:30 -0700772 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
773 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700774
Ray Milkey269ffb92014-04-03 14:43:30 -0700775 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
776 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800777
Ray Milkey269ffb92014-04-03 14:43:30 -0700778 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800779
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700780 flowPath.setInstallerId(callerId);
pingping-linba5c52f2014-02-11 16:52:01 -0800781
Ray Milkey269ffb92014-04-03 14:43:30 -0700782 // Set flowPath FlowPathType and FlowPathUserState
783 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
784 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800785
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700786 // Insert the dest-mac based forwarding flow entry to the non-first-hop
787 // switches
Ray Milkey269ffb92014-04-03 14:43:30 -0700788 FlowPathFlags flowPathFlags = new FlowPathFlags();
789 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
790 flowPath.setFlowPathFlags(flowPathFlags);
791
792 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700793 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700794 new SwitchPort(new Dpid(dstInterface.getDpid()),
795 new PortNumber(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800796
Ray Milkey269ffb92014-04-03 14:43:30 -0700797 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800798
Ray Milkey269ffb92014-04-03 14:43:30 -0700799 if (dstInterface.equals(srcInterface)) {
800 continue;
801 }
pingping-linba5c52f2014-02-11 16:52:01 -0800802
Ray Milkey269ffb92014-04-03 14:43:30 -0700803 // Create flowPath FlowId
804 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800805
Ray Milkey269ffb92014-04-03 14:43:30 -0700806 // Create the DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700807 SwitchPort srcPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700808 new SwitchPort(new Dpid(srcInterface.getDpid()),
809 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800810
Ray Milkey269ffb92014-04-03 14:43:30 -0700811 DataPath dataPath = new DataPath();
812 dataPath.setSrcPort(srcPort);
813 dataPath.setDstPort(dstPort);
814 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800815
Ray Milkey269ffb92014-04-03 14:43:30 -0700816 // Create the Flow Path Match condition(s)
817 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700818 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700819 flowEntryMatch.enableDstMac(dstMacAddress);
820 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800821
Ray Milkey269ffb92014-04-03 14:43:30 -0700822 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700823 // Shortest Path Flow, and is always the last action for the Flow
824 // Entries
Ray Milkey269ffb92014-04-03 14:43:30 -0700825 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
826 // TODO: Add the flow by using the new Path Intent framework
827 /*
828 if (flowManagerService.addFlow(flowPath) == null) {
829 log.error("Failed to set up MAC based forwarding path to {}, {}",
830 path.getDstIpAddress().getHostAddress(),dstMacAddress);
831 }
832 else {
833 log.debug("Successfully set up MAC based forwarding path to {}, {}",
834 path.getDstIpAddress().getHostAddress(),dstMacAddress);
835 }
836 */
837 }
838 }
pingping-linba5c52f2014-02-11 16:52:01 -0800839
Komal Shah399a2922014-05-28 01:57:40 -0700840 @Override
841 public void beginRoutingNew() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700842 setupBgpPathsNew();
Komal Shah399a2922014-05-28 01:57:40 -0700843
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700844 // setupFullMesh();
Komal Shah399a2922014-05-28 01:57:40 -0700845
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700846 // Suppress link discovery on external-facing router ports
Komal Shah399a2922014-05-28 01:57:40 -0700847
848 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -0700849 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Komal Shah399a2922014-05-28 01:57:40 -0700850 }
851
852 bgpUpdatesExecutor.execute(new Runnable() {
853 @Override
854 public void run() {
855 doUpdatesThread();
856 }
857 });
858 }
859
Ray Milkey269ffb92014-04-03 14:43:30 -0700860 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700861 * Setup the Paths to the BGP Daemon. Run a loop for all of the bgpPeers
862 * Push flow from BGPd to the peer Push flow from peer to BGPd Parameters to
863 * pass to the intent are as follows: String id, long srcSwitch, long
864 * srcPort, long srcMac, int srcIP, long dstSwitch, long dstPort, long
865 * dstMac, int dstIP
Komal Shah399a2922014-05-28 01:57:40 -0700866 */
867 private void setupBgpPathsNew() {
868 IntentOperationList operations = new IntentOperationList();
869 for (BgpPeer bgpPeer : bgpPeers.values()) {
870 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700871 // Inet4Address.
Komal Shah399a2922014-05-28 01:57:40 -0700872 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
873 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700874 String fwdIntentId = caller + ":"
875 + controllerRegistryService.getNextUniqueId();
876 String bwdIntentId = caller + ":"
877 + controllerRegistryService.getNextUniqueId();
Komal Shah399a2922014-05-28 01:57:40 -0700878 SwitchPort srcPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700879 new SwitchPort(bgpdAttachmentPoint.dpid(),
880 bgpdAttachmentPoint.port());
Komal Shah399a2922014-05-28 01:57:40 -0700881 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700882 new SwitchPort(new Dpid(peerInterface.getDpid()),
883 new PortNumber(peerInterface.getSwitchPort().port()));
Komal Shah399a2922014-05-28 01:57:40 -0700884 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700885 srcPort.dpid().value(), srcPort.port().value(),
886 ShortestPathIntent.EMPTYMACADDRESS, srcIP,
887 dstPort.dpid().value(), dstPort.port().value(),
888 ShortestPathIntent.EMPTYMACADDRESS, dstIP);
Komal Shah399a2922014-05-28 01:57:40 -0700889 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700890 dstPort.dpid().value(), dstPort.port().value(),
891 ShortestPathIntent.EMPTYMACADDRESS, dstIP,
892 srcPort.dpid().value(), srcPort.port().value(),
893 ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700894 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
895 operations.add(operator, fwdIntent);
896 operations.add(operator, bwdIntent);
897 }
898 pathRuntime.executeIntentOperations(operations);
899 }
900
901 /*
Jonathan Hart938a0152014-04-07 18:27:31 -0700902 * Proactively install all BGP traffic paths from BGP host attachment point
Ray Milkeyb41100a2014-04-10 10:42:15 -0700903 * in SDN network to all the virtual gateways to BGP peers in other networks.
Ray Milkey269ffb92014-04-03 14:43:30 -0700904 */
905 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200906
Ray Milkey269ffb92014-04-03 14:43:30 -0700907 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800908
Ray Milkey269ffb92014-04-03 14:43:30 -0700909 FlowPath flowPath = new FlowPath();
Sho SHIMIZU9ec39822014-07-10 17:15:12 -0700910 flowPath.setInstallerId(callerId);
pingping-linba5c52f2014-02-11 16:52:01 -0800911
Ray Milkey269ffb92014-04-03 14:43:30 -0700912 // Set flowPath FlowPathType and FlowPathUserState
913 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
914 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800915
Ray Milkey269ffb92014-04-03 14:43:30 -0700916 // Install flow paths between BGPd and its peers
917 // There is no need to set the FlowPathFlags
918 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800919
Ray Milkey269ffb92014-04-03 14:43:30 -0700920 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Ray Milkey269ffb92014-04-03 14:43:30 -0700921 // Create the Flow Path Match condition(s)
922 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700923 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
pingping-linba5c52f2014-02-11 16:52:01 -0800924
Ray Milkey269ffb92014-04-03 14:43:30 -0700925 // Match both source address and dest address
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700926 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress()
927 + "/32");
Komal Shah399a2922014-05-28 01:57:40 -0700928
Ray Milkey269ffb92014-04-03 14:43:30 -0700929 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800930
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700931 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress()
932 .getHostAddress() + "/32");
Ray Milkey269ffb92014-04-03 14:43:30 -0700933 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800934
Ray Milkey269ffb92014-04-03 14:43:30 -0700935 // Match TCP protocol
936 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800937
Ray Milkey269ffb92014-04-03 14:43:30 -0700938 // Match destination TCP port
939 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
940 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800941
Ray Milkey269ffb92014-04-03 14:43:30 -0700942 /**
943 * Create the DataPath: BGP -> BGP peer
944 */
945 // Flow path for src-TCP-port
946 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800947
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700948 SwitchPort srcPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700949 new SwitchPort(bgpdAttachmentPoint.dpid(),
950 bgpdAttachmentPoint.port());
Ray Milkey269ffb92014-04-03 14:43:30 -0700951 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800952
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700953 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700954 new SwitchPort(new Dpid(peerInterface.getDpid()),
955 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700956 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800957
Ray Milkey269ffb92014-04-03 14:43:30 -0700958 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800959
Ray Milkey269ffb92014-04-03 14:43:30 -0700960 // TODO: Add the flow by using the new Path Intent framework
961 /*
962 if (flowManagerService.addFlow(flowPath) == null) {
963 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
964 bgpPeer.getIpAddress().getHostAddress());
965 }
966 else {
967 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
968 bgpPeer.getIpAddress().getHostAddress());
969 }
970 */
pingping-linba5c52f2014-02-11 16:52:01 -0800971
Ray Milkey269ffb92014-04-03 14:43:30 -0700972 // Disable dst-TCP-port, and set src-TCP-port
973 flowEntryMatch.disableDstTcpUdpPort();
974 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
975 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800976
Ray Milkey269ffb92014-04-03 14:43:30 -0700977 // Create a new FlowId
978 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800979
Ray Milkey269ffb92014-04-03 14:43:30 -0700980 // TODO: Add the flow by using the new Path Intent framework
981 /*
982 if (flowManagerService.addFlow(flowPath) == null) {
983 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
984 bgpPeer.getIpAddress().getHostAddress());
985 }
986 else {
987 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
988 bgpPeer.getIpAddress().getHostAddress());
989 }
990 */
pingping-linba5c52f2014-02-11 16:52:01 -0800991
Ray Milkey269ffb92014-04-03 14:43:30 -0700992 /**
993 * Create the DataPath: BGP <-BGP peer
994 */
995 // Reversed BGP flow path for src-TCP-port
996 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800997
Ray Milkey2476cac2014-04-08 11:03:21 -0700998 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800999
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -07001000 SwitchPort reverseDstPort =
Komal Shah399a2922014-05-28 01:57:40 -07001001 new SwitchPort(bgpdAttachmentPoint.dpid(),
1002 bgpdAttachmentPoint.port());
Ray Milkey2476cac2014-04-08 11:03:21 -07001003 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -08001004
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -07001005 SwitchPort reverseSrcPort =
Komal Shah399a2922014-05-28 01:57:40 -07001006 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -07001007 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey2476cac2014-04-08 11:03:21 -07001008 reverseDataPath.setSrcPort(reverseSrcPort);
1009 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001010
Jonathan Hart938a0152014-04-07 18:27:31 -07001011 // Reverse the dst IP and src IP addresses
Ray Milkey269ffb92014-04-03 14:43:30 -07001012 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
1013 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
1014 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001015
Ray Milkey269ffb92014-04-03 14:43:30 -07001016 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001017
Ray Milkey269ffb92014-04-03 14:43:30 -07001018 // TODO: Add the flow by using the new Path Intent framework
1019 /*
1020 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001021
Ray Milkey269ffb92014-04-03 14:43:30 -07001022 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
1023 bgpPeer.getIpAddress().getHostAddress());
1024 }
1025 else {
1026 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
1027 bgpPeer.getIpAddress().getHostAddress());
1028 }
1029 */
pingping-linba5c52f2014-02-11 16:52:01 -08001030
Ray Milkey269ffb92014-04-03 14:43:30 -07001031 // Reversed BGP flow path for dst-TCP-port
1032 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001033
Ray Milkey269ffb92014-04-03 14:43:30 -07001034 // Disable src-TCP-port, and set the dst-TCP-port
1035 flowEntryMatch.disableSrcTcpUdpPort();
1036 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
1037 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001038
Ray Milkey269ffb92014-04-03 14:43:30 -07001039 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001040
Ray Milkey269ffb92014-04-03 14:43:30 -07001041 // TODO: Add the flow by using the new Path Intent framework
1042 /*
1043 if (flowManagerService.addFlow(flowPath) == null) {
1044 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1045 bgpPeer.getIpAddress().getHostAddress());
1046 }
1047 else {
1048 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1049 bgpPeer.getIpAddress().getHostAddress());
1050 }
1051 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001052
Ray Milkey269ffb92014-04-03 14:43:30 -07001053 /**
1054 * ICMP paths between BGPd and its peers
1055 */
Jonathan Hart938a0152014-04-07 18:27:31 -07001056 // match ICMP protocol BGP <- Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001057 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001058
Ray Milkey269ffb92014-04-03 14:43:30 -07001059 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
1060 flowEntryMatch.disableSrcTcpUdpPort();
1061 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -08001062
Ray Milkey269ffb92014-04-03 14:43:30 -07001063 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001064
Ray Milkey2476cac2014-04-08 11:03:21 -07001065 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001066
Ray Milkey269ffb92014-04-03 14:43:30 -07001067 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001068
Ray Milkey269ffb92014-04-03 14:43:30 -07001069 // TODO: Add the flow by using the new Path Intent framework
1070 /*
1071 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001072
Ray Milkey269ffb92014-04-03 14:43:30 -07001073 log.error("Failed to set up ICMP path BGP <- Peer {}",
1074 bgpPeer.getIpAddress().getHostAddress());
1075 }
1076 else {
1077 log.debug("Successfully set up ICMP path BGP <- Peer {}",
1078 bgpPeer.getIpAddress().getHostAddress());
1079 }
1080 */
pingping-linba5c52f2014-02-11 16:52:01 -08001081
Jonathan Hart938a0152014-04-07 18:27:31 -07001082 // match ICMP protocol BGP -> Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001083 flowPath.setFlowId(new FlowId());
Ray Milkey269ffb92014-04-03 14:43:30 -07001084 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
1085 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
1086 flowPath.setFlowEntryMatch(flowEntryMatch);
Ray Milkey269ffb92014-04-03 14:43:30 -07001087 flowPath.setDataPath(dataPath);
Ray Milkey269ffb92014-04-03 14:43:30 -07001088 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001089
Ray Milkey269ffb92014-04-03 14:43:30 -07001090 // TODO: Add the flow by using the new Path Intent framework
1091 /*
1092 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001093
Ray Milkey269ffb92014-04-03 14:43:30 -07001094 log.error("Failed to set up ICMP path BGP -> Peer {}",
1095 bgpPeer.getIpAddress().getHostAddress());
1096 }
1097 else {
1098 log.debug("Successfully set up ICMP path BGP -> Peer {}",
1099 bgpPeer.getIpAddress().getHostAddress());
1100 }
1101 */
1102 }
1103 }
pingping-linba5c52f2014-02-11 16:52:01 -08001104
Ray Milkey269ffb92014-04-03 14:43:30 -07001105 @Override
1106 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
1107 log.debug("Received ARP response: {} => {}",
1108 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001109
Ray Milkey269ffb92014-04-03 14:43:30 -07001110 /*
1111 * We synchronize on this to prevent changes to the ptree while we're pushing
1112 * flows to the switches. If the ptree changes, the ptree and switches
1113 * could get out of sync.
1114 */
1115 synchronized (this) {
1116 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001117
Ray Milkey269ffb92014-04-03 14:43:30 -07001118 if (path != null) {
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -07001119 log.debug("Pushing path to {} at {} on {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001120 path.getDstIpAddress().getHostAddress(), macAddress,
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -07001121 path.getDstInterface().getSwitchPort());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001122 // These paths should always be to BGP peers. Paths to non-peers
1123 // are
Jonathan Hart938a0152014-04-07 18:27:31 -07001124 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -07001125 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001126 // A path already got pushed to this endpoint while we were
1127 // waiting
1128 // for ARP. We'll copy over the permanent attribute if it is
1129 // set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -07001130 if (path.isPermanent()) {
1131 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1132 }
1133 } else {
1134 calculateAndPushPath(path, macAddress);
1135 pushedPaths.put(path.getDstIpAddress(), path);
1136 }
1137 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001138
Ray Milkey269ffb92014-04-03 14:43:30 -07001139 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001140
Ray Milkey269ffb92014-04-03 14:43:30 -07001141 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001142 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001143
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001144 RibEntry rib = bgpRoutes.getValueForExactKey(
1145 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -07001146 if (rib != null && rib.equals(update.getRibEntry())) {
1147 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1148 rib.getNextHop().getHostAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001149 // We only push prefix flows if the prefix is still in the
1150 // ptree
1151 // and the next hop is the same as our update. The prefix
1152 // could
1153 // have been removed while we were waiting for the ARP, or
1154 // the
Jonathan Hart938a0152014-04-07 18:27:31 -07001155 // next hop could have changed.
Ray Milkey7531a342014-04-11 15:08:12 -07001156 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -07001157 } else {
1158 log.debug("Received ARP response, but {},{} is no longer in ptree",
1159 update.getPrefix(), update.getRibEntry());
1160 }
1161 }
1162 }
1163 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001164
Jonathan Hart938a0152014-04-07 18:27:31 -07001165 // TODO wait the priority module of the flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001166 private void setupArpFlows() {
1167 OFMatch match = new OFMatch();
1168 match.setDataLayerType(Ethernet.TYPE_ARP);
1169 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001170
Ray Milkey269ffb92014-04-03 14:43:30 -07001171 OFFlowMod fm = new OFFlowMod();
1172 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001173
Ray Milkey269ffb92014-04-03 14:43:30 -07001174 OFActionOutput action = new OFActionOutput();
1175 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1176 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001177 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -07001178 actions.add(action);
1179 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001180
Ray Milkey269ffb92014-04-03 14:43:30 -07001181 fm.setIdleTimeout((short) 0)
1182 .setHardTimeout((short) 0)
1183 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1184 .setCookie(0)
1185 .setCommand(OFFlowMod.OFPFC_ADD)
1186 .setPriority(ARP_PRIORITY)
1187 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001188
Ray Milkey269ffb92014-04-03 14:43:30 -07001189 for (String strdpid : switches) {
1190 flowCache.write(HexString.toLong(strdpid), fm);
1191 }
1192 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001193
Jonathan Hart938a0152014-04-07 18:27:31 -07001194 // TODO need update, waiting for the priority feature from flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001195 private void setupDefaultDropFlows() {
1196 OFFlowMod fm = new OFFlowMod();
1197 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -07001198 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001199
Ray Milkey269ffb92014-04-03 14:43:30 -07001200 fm.setIdleTimeout((short) 0)
1201 .setHardTimeout((short) 0)
1202 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1203 .setCookie(0)
1204 .setCommand(OFFlowMod.OFPFC_ADD)
1205 .setPriority((short) 0)
1206 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001207
Ray Milkey269ffb92014-04-03 14:43:30 -07001208 OFFlowMod fmLLDP;
1209 OFFlowMod fmBDDP;
1210 try {
1211 fmLLDP = fm.clone();
1212 fmBDDP = fm.clone();
1213 } catch (CloneNotSupportedException e1) {
1214 log.error("Error cloning flow mod", e1);
1215 return;
1216 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001217
Ray Milkey269ffb92014-04-03 14:43:30 -07001218 OFMatch matchLLDP = new OFMatch();
1219 matchLLDP.setDataLayerType((short) 0x88cc);
1220 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1221 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001222
Ray Milkey269ffb92014-04-03 14:43:30 -07001223 OFMatch matchBDDP = new OFMatch();
1224 matchBDDP.setDataLayerType((short) 0x8942);
1225 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1226 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001227
Ray Milkey269ffb92014-04-03 14:43:30 -07001228 OFActionOutput action = new OFActionOutput();
1229 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1230 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001231 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -07001232 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001233
Ray Milkey269ffb92014-04-03 14:43:30 -07001234 fmLLDP.setActions(actions);
1235 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001236
Ray Milkey269ffb92014-04-03 14:43:30 -07001237 fmLLDP.setPriority(ARP_PRIORITY);
1238 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1239 fmBDDP.setPriority(ARP_PRIORITY);
1240 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001241
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001242 List<OFFlowMod> flowModList = new ArrayList<>(3);
Ray Milkey269ffb92014-04-03 14:43:30 -07001243 flowModList.add(fm);
1244 flowModList.add(fmLLDP);
1245 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001246
Ray Milkey269ffb92014-04-03 14:43:30 -07001247 for (String strdpid : switches) {
1248 flowCache.write(HexString.toLong(strdpid), flowModList);
1249 }
1250 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001251
Ray Milkey269ffb92014-04-03 14:43:30 -07001252 private void beginRouting() {
1253 log.debug("Topology is now ready, beginning routing function");
1254 // TODO: Fix for the new Topology Network Graph
1255 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001256
Ray Milkey269ffb92014-04-03 14:43:30 -07001257 // Wait Pavlin's API. We need the following functions.
1258 /*setupArpFlows();
1259 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001260
Ray Milkey269ffb92014-04-03 14:43:30 -07001261 setupBgpPaths();
1262 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001263
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001264 // Suppress link discovery on external-facing router ports
Ray Milkey269ffb92014-04-03 14:43:30 -07001265 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -07001266 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001267 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001268
Ray Milkey269ffb92014-04-03 14:43:30 -07001269 bgpUpdatesExecutor.execute(new Runnable() {
1270 @Override
1271 public void run() {
1272 doUpdatesThread();
1273 }
1274 });
1275 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001276
Jonathan Hart938a0152014-04-07 18:27:31 -07001277 // Before inserting the paths for BGP traffic, we should check whether
1278 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001279 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001280 // TODO: Fix the code below after topoSwitchSerice was removed
1281 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001282 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001283
Ray Milkey269ffb92014-04-03 14:43:30 -07001284 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1285 getActiveSwitches().iterator();
1286 while(activeSwitches.hasNext())
1287 {
1288 ISwitchObject switchObject = activeSwitches.next();
1289 if (switchObject.getDPID().equals(dpid)) {
1290 break;
1291 }
1292 if(activeSwitches.hasNext() == false) {
1293 log.debug("Not all switches are here yet");
1294 return;
1295 }
1296 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001297 }
1298 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001299 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001300 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001301
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001302 // Actually we only need to go half way round to verify full mesh
1303 // connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001304 private void checkTopologyReady() {
1305 for (Interface dstInterface : interfaces.values()) {
1306 for (Interface srcInterface : interfaces.values()) {
1307 if (dstInterface.equals(srcInterface)) {
1308 continue;
1309 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001310
Ray Milkey269ffb92014-04-03 14:43:30 -07001311 // TODO: Fix for the new Topology Network Graph
1312 /*
1313 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1314 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001315
Ray Milkey269ffb92014-04-03 14:43:30 -07001316 if (shortestPath == null){
1317 log.debug("Shortest path between {} and {} not found",
1318 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1319 return;
1320 }
1321 */
1322 }
1323 }
1324 topologyReady = true;
1325 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001326
Ray Milkey269ffb92014-04-03 14:43:30 -07001327 private void checkStatus() {
1328 if (!switchesConnected) {
1329 checkSwitchesConnected();
1330 }
1331 boolean oldTopologyReadyStatus = topologyReady;
1332 if (switchesConnected && !topologyReady) {
1333 checkTopologyReady();
1334 }
1335 if (!oldTopologyReadyStatus && topologyReady) {
1336 beginRouting();
1337 }
1338 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001339
Ray Milkey269ffb92014-04-03 14:43:30 -07001340 private void doUpdatesThread() {
1341 boolean interrupted = false;
1342 try {
1343 while (true) {
1344 try {
1345 RibUpdate update = ribUpdates.take();
1346 switch (update.getOperation()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001347 case UPDATE:
1348 if (validateUpdate(update)) {
1349 processRibAdd(update);
1350 } else {
1351 log.debug("Rib UPDATE out of order: {} via {}",
1352 update.getPrefix(), update.getRibEntry().getNextHop());
1353 }
1354 break;
1355 case DELETE:
1356 if (validateUpdate(update)) {
1357 processRibDelete(update);
1358 } else {
1359 log.debug("Rib DELETE out of order: {} via {}",
1360 update.getPrefix(), update.getRibEntry().getNextHop());
1361 }
1362 break;
1363 default:
1364 log.error("Unknown operation {}", update.getOperation());
1365 break;
Ray Milkey269ffb92014-04-03 14:43:30 -07001366 }
1367 } catch (InterruptedException e) {
1368 log.debug("Interrupted while taking from updates queue", e);
1369 interrupted = true;
1370 } catch (Exception e) {
1371 log.debug("exception", e);
1372 }
1373 }
1374 } finally {
1375 if (interrupted) {
1376 Thread.currentThread().interrupt();
1377 }
1378 }
1379 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001380
Ray Milkey269ffb92014-04-03 14:43:30 -07001381 private boolean validateUpdate(RibUpdate update) {
1382 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001383 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
1384 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001385
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001386 // If there is no existing entry we must assume this is the most recent
1387 // update. However this might not always be the case as we might have a
1388 // POST then DELETE reordering.
1389 // if (oldEntry == null ||
1390 // !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001391 if (oldEntry == null) {
1392 return true;
1393 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001394
Ray Milkey269ffb92014-04-03 14:43:30 -07001395 // This handles the case where routes are gathered in the initial
1396 // request because they don't have sequence number info
1397 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1398 return true;
1399 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001400
Ray Milkey269ffb92014-04-03 14:43:30 -07001401 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1402 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001403 }
Ray Milkey4985f212014-04-10 16:57:05 -07001404
1405 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001406 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -07001407 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001408
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001409 private Interface longestInterfacePrefixMatch(InetAddress address) {
1410 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
1411 Prefix.MAX_PREFIX_LENGTH);
1412 Iterator<Interface> it =
1413 interfaceRoutes.getValuesForKeysPrefixing(
1414 prefixToSearchFor.toBinaryString()).iterator();
1415 Interface intf = null;
1416 // Find the last prefix, which will be the longest prefix
1417 while (it.hasNext()) {
1418 intf = it.next();
1419 }
1420
1421 return intf;
1422 }
1423
Ray Milkey269ffb92014-04-03 14:43:30 -07001424 // The code below should be reimplemented after removal of Floodlight's
1425 // ITopologyService API. It should be implemented on top of network graph
1426 // notifications. (It was pretty hacky anyway...)
1427 /*
1428 @Override
1429 public void topologyChanged() {
1430 if (topologyReady) {
1431 return;
1432 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001433
Ray Milkey269ffb92014-04-03 14:43:30 -07001434 boolean refreshNeeded = false;
1435 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1436 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1437 //We don't need to recalculate anything for just link updates
1438 //They happen very frequently
1439 refreshNeeded = true;
1440 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001441
Ray Milkey269ffb92014-04-03 14:43:30 -07001442 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001443
Ray Milkey269ffb92014-04-03 14:43:30 -07001444 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1445 synchronized (linkUpdates) {
1446 linkUpdates.add(ldu);
1447 }
1448 }
1449 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001450
Ray Milkey269ffb92014-04-03 14:43:30 -07001451 if (refreshNeeded && !topologyReady){
1452 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1453 }
1454 }
1455 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001456
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001457 // ******************
1458 // IOFSwitchListener
1459 // ******************
1460
Ray Milkey269ffb92014-04-03 14:43:30 -07001461 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001462 public void switchActivatedMaster(long swId) {
1463 IOFSwitch sw = floodlightProvider.getSwitch(swId);
1464 if (sw == null) {
1465 log.warn("Added switch not available {} ", swId);
1466 return;
1467 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001468 if (!topologyReady) {
1469 sw.clearAllFlowMods();
1470 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001471
Ray Milkey269ffb92014-04-03 14:43:30 -07001472 flowCache.switchConnected(sw);
1473 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001474
Ray Milkey269ffb92014-04-03 14:43:30 -07001475 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001476 public void switchActivatedEqual(long swId) {
1477 // TODO Auto-generated method stub
1478
1479 }
1480
1481 @Override
1482 public void switchMasterToEqual(long swId) {
1483 // TODO Auto-generated method stub
1484
1485 }
1486
1487 @Override
1488 public void switchEqualToMaster(long swId) {
1489 // for now treat as switchActivatedMaster
1490 switchActivatedMaster(swId);
1491 }
1492
1493 @Override
1494 public void switchDisconnected(long swId) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001495 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001496 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001497
Ray Milkey269ffb92014-04-03 14:43:30 -07001498 @Override
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001499 public void switchPortChanged(long swId, OFPortDesc port, PortChangeType pct) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001500 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001501 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001502
Ray Milkey269ffb92014-04-03 14:43:30 -07001503 @Override
1504 public String getName() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001505 return "sdnip";
Ray Milkey269ffb92014-04-03 14:43:30 -07001506 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001507
Ray Milkey269ffb92014-04-03 14:43:30 -07001508 /*
1509 * IConfigInfoService methods
1510 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001511
Ray Milkey269ffb92014-04-03 14:43:30 -07001512 @Override
1513 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001514 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001515 return (intf != null && intf.getIpAddress().equals(address));
1516 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001517
Ray Milkey269ffb92014-04-03 14:43:30 -07001518 @Override
1519 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001520 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001521 return (intf != null && !intf.getIpAddress().equals(address));
1522 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001523
Ray Milkey269ffb92014-04-03 14:43:30 -07001524 @Override
1525 public boolean fromExternalNetwork(long inDpid, short inPort) {
1526 for (Interface intf : interfaces.values()) {
1527 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1528 return true;
1529 }
1530 }
1531 return false;
1532 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001533
Ray Milkey269ffb92014-04-03 14:43:30 -07001534 @Override
1535 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001536 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -07001537 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001538
Ray Milkey269ffb92014-04-03 14:43:30 -07001539 @Override
1540 public boolean hasLayer3Configuration() {
1541 return !interfaces.isEmpty();
1542 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001543
Ray Milkey269ffb92014-04-03 14:43:30 -07001544 @Override
1545 public MACAddress getRouterMacAddress() {
1546 return bgpdMacAddress;
1547 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001548
Ray Milkey269ffb92014-04-03 14:43:30 -07001549 @Override
1550 public short getVlan() {
1551 return vlan;
1552 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001553}