blob: e130e6702df7de7bbac3de782407404f990dcc2e [file] [log] [blame]
Jonathan Hart8f6dc092014-04-18 15:56:43 -07001package net.onrc.onos.apps.sdnip;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
Jonathan Hartd1f23252013-06-13 15:17:05 +12003import java.io.File;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07004import java.io.IOException;
5import java.net.InetAddress;
pingping-lina2cbfad2013-03-07 08:39:21 +08006import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07007import java.util.Collection;
pingping-lina2cbfad2013-03-07 08:39:21 +08008import java.util.HashMap;
Jonathan Hartf6978ce2014-06-23 11:20:04 -07009import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070010import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070011import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120012import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120013import java.util.concurrent.BlockingQueue;
14import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120015import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120016import java.util.concurrent.LinkedBlockingQueue;
pingping-lina2cbfad2013-03-07 08:39:21 +080017
Jonathan Hart61ba9372013-05-19 20:10:29 -070018import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070019import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart64c0b202013-08-20 15:45:07 +120020import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080021import net.floodlightcontroller.core.module.FloodlightModuleContext;
22import net.floodlightcontroller.core.module.FloodlightModuleException;
23import net.floodlightcontroller.core.module.IFloodlightModule;
24import net.floodlightcontroller.core.module.IFloodlightService;
pingping-lina2cbfad2013-03-07 08:39:21 +080025import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120026import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0961fe82014-04-03 09:56:25 -070027import net.onrc.onos.apps.proxyarp.IArpRequester;
28import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart8f6dc092014-04-18 15:56:43 -070029import net.onrc.onos.apps.sdnip.RibUpdate.Operation;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070030import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutable;
Komal Shah399a2922014-05-28 01:57:40 -070031import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutableNew;
32import net.onrc.onos.core.intent.IntentOperation;
33import net.onrc.onos.core.intent.IntentOperationList;
34import net.onrc.onos.core.intent.ShortestPathIntent;
35import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
Jonathan Harta99ec672014-04-03 11:30:34 -070036import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070037import net.onrc.onos.core.main.config.IConfigInfoService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070038import net.onrc.onos.core.packet.Ethernet;
39import net.onrc.onos.core.packet.IPv4;
Komal Shah399a2922014-05-28 01:57:40 -070040import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart23701d12014-04-03 10:45:48 -070041import net.onrc.onos.core.util.CallerId;
42import net.onrc.onos.core.util.DataPath;
43import net.onrc.onos.core.util.Dpid;
44import net.onrc.onos.core.util.FlowEntryAction;
45import net.onrc.onos.core.util.FlowEntryActions;
46import net.onrc.onos.core.util.FlowEntryMatch;
47import net.onrc.onos.core.util.FlowId;
48import net.onrc.onos.core.util.FlowPath;
49import net.onrc.onos.core.util.FlowPathFlags;
50import net.onrc.onos.core.util.FlowPathType;
51import net.onrc.onos.core.util.FlowPathUserState;
52import net.onrc.onos.core.util.IPv4Net;
Yuta HIGUCHIfb564502014-06-16 21:29:00 -070053import net.onrc.onos.core.util.PortNumber;
Jonathan Hart23701d12014-04-03 10:45:48 -070054import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080055import net.sf.json.JSONArray;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070056import net.sf.json.JSONException;
pingping-line2a09ca2013-03-23 09:33:58 +080057import net.sf.json.JSONObject;
58import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080059
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070060import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120061import org.codehaus.jackson.JsonParseException;
62import org.codehaus.jackson.map.JsonMappingException;
63import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070064import org.openflow.protocol.OFFlowMod;
65import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070066import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120067import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070068import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070069import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120070import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080071import org.slf4j.Logger;
72import org.slf4j.LoggerFactory;
73
Jonathan Hart4dfc3652013-08-02 20:22:36 +120074import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120075import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120076import com.google.common.collect.Multimaps;
77import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120078import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120079import com.google.common.util.concurrent.ThreadFactoryBuilder;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070080import com.googlecode.concurrenttrees.radix.RadixTree;
81import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
82import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
83import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120084
Jonathan Hart8f6dc092014-04-18 15:56:43 -070085public class SdnIp implements IFloodlightModule, ISdnIpService,
Ray Milkey269ffb92014-04-03 14:43:30 -070086 IArpRequester,
87 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070088
Jonathan Hart8f6dc092014-04-18 15:56:43 -070089 private static final Logger log = LoggerFactory.getLogger(SdnIp.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080090
Ray Milkey269ffb92014-04-03 14:43:30 -070091 private IFloodlightProviderService floodlightProvider;
92 private ILinkDiscoveryService linkDiscoveryService;
93 private IRestApiService restApi;
94 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070095
Jonathan Hartf6978ce2014-06-23 11:20:04 -070096 private InvertedRadixTree<RibEntry> bgpRoutes;
97 private InvertedRadixTree<Interface> interfaceRoutes;
98
Ray Milkey269ffb92014-04-03 14:43:30 -070099 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700100
Ray Milkey269ffb92014-04-03 14:43:30 -0700101 private String bgpdRestIp;
102 private String routerId;
Ray Milkey5df613b2014-04-15 10:50:56 -0700103 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
104 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700105
Komal Shah399a2922014-05-28 01:57:40 -0700106 /* ShortestPath Intent Variables */
107 private final String callerId = "SdnIp";
108 private IControllerRegistryService controllerRegistryService;
109 private IPathCalcRuntimeService pathRuntime;
110 /* Shortest Intent Path Variables */
111
Ray Milkey2476cac2014-04-08 11:03:21 -0700112 private static final short ARP_PRIORITY = 20;
Ray Milkey5d406012014-04-08 14:44:41 -0700113
Jonathan Hart938a0152014-04-07 18:27:31 -0700114 // The fields below are unused after the move to FlowManager.
115 // Remove them if no longer needed.
116 /*
117 // We need to identify our flows somehow, in lieu of an OS-wide mechanism
118 // to hand out cookie IDs to prevent conflicts.
119 private static final long APP_COOKIE = 0xa0000000000000L;
120 // Cookie for flows that do L2 forwarding within SDN domain to egress routers
121 private static final long L2_FWD_COOKIE = APP_COOKIE + 1;
122 // Cookie for flows in ingress switches that rewrite the MAC address
123 private static final long MAC_RW_COOKIE = APP_COOKIE + 2;
124 // Cookie for flows that setup BGP paths
125 private static final long BGP_COOKIE = APP_COOKIE + 3;
126 // Forwarding uses priority 0, and the mac rewrite entries in ingress switches
127 // need to be higher priority than this otherwise the rewrite may not get done
128 private static final short SDNIP_PRIORITY = 10;
129 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700130
Ray Milkey2476cac2014-04-08 11:03:21 -0700131 private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700132
Jonathan Hart938a0152014-04-07 18:27:31 -0700133 private static final int TOPO_DETECTION_WAIT = 2; // seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700134
Jonathan Hart938a0152014-04-07 18:27:31 -0700135 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700136 private List<String> switches;
137 private Map<String, Interface> interfaces;
138 private Map<InetAddress, BgpPeer> bgpPeers;
139 private SwitchPort bgpdAttachmentPoint;
140 private MACAddress bgpdMacAddress;
141 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700142
Jonathan Hart938a0152014-04-07 18:27:31 -0700143 // True when all switches have connected
Ray Milkey269ffb92014-04-03 14:43:30 -0700144 private volatile boolean switchesConnected = false;
Jonathan Hart938a0152014-04-07 18:27:31 -0700145 // True when we have a full mesh of shortest paths between gateways
Ray Milkey269ffb92014-04-03 14:43:30 -0700146 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200147
Jonathan Hart284e70f2014-07-05 12:32:51 -0700148 //private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700149
Ray Milkey269ffb92014-04-03 14:43:30 -0700150 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700151
Ray Milkey269ffb92014-04-03 14:43:30 -0700152 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700153
Ray Milkey269ffb92014-04-03 14:43:30 -0700154 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700155
Ray Milkey269ffb92014-04-03 14:43:30 -0700156 private Map<InetAddress, Path> pushedPaths;
157 private Map<Prefix, Path> prefixToPath;
158 // private Multimap<Prefix, PushedFlowMod> pushedFlows;
159 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700160
Ray Milkey269ffb92014-04-03 14:43:30 -0700161 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700162
Ray Milkey269ffb92014-04-03 14:43:30 -0700163 // TODO: Fix for the new Topology Network Graph
164 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700165
Jonathan Hart284e70f2014-07-05 12:32:51 -0700166 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700167 private class TopologyChangeDetector implements Runnable {
168 @Override
169 public void run() {
170 log.debug("Running topology change detection task");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700171 // TODO: Fix the code below after topoLinkService was removed
Ray Milkey269ffb92014-04-03 14:43:30 -0700172 synchronized (linkUpdates) {
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700173
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700175
Ray Milkey269ffb92014-04-03 14:43:30 -0700176 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700177
Ray Milkey269ffb92014-04-03 14:43:30 -0700178 Iterator<LDUpdate> it = linkUpdates.iterator();
179 while (it.hasNext()){
180 LDUpdate ldu = it.next();
181 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
182 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700183
Ray Milkey269ffb92014-04-03 14:43:30 -0700184 if (activeLinks.contains(l)){
185 it.remove();
186 }
187 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700188 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700189
Ray Milkey269ffb92014-04-03 14:43:30 -0700190 if (!topologyReady) {
191 if (linkUpdates.isEmpty()) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700192 // All updates have been seen in network map.
193 // We can check if topology is ready
Ray Milkey269ffb92014-04-03 14:43:30 -0700194 log.debug("No known changes outstanding. Checking topology now");
195 checkStatus();
196 } else {
Jonathan Hart938a0152014-04-07 18:27:31 -0700197 // We know of some link updates that haven't propagated to the database yet
Ray Milkey269ffb92014-04-03 14:43:30 -0700198 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
199 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
200 }
201 }
202 }
203 }
Jonathan Hart284e70f2014-07-05 12:32:51 -0700204 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700205
Ray Milkey269ffb92014-04-03 14:43:30 -0700206 private void readConfiguration(String configFilename) {
207 File gatewaysFile = new File(configFilename);
208 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700209
Ray Milkey269ffb92014-04-03 14:43:30 -0700210 try {
211 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700212
Ray Milkey269ffb92014-04-03 14:43:30 -0700213 switches = config.getSwitches();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700214 interfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700215 for (Interface intf : config.getInterfaces()) {
216 interfaces.put(intf.getName(), intf);
217 }
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700218 bgpPeers = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700219 for (BgpPeer peer : config.getPeers()) {
220 bgpPeers.put(peer.getIpAddress(), peer);
221 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700222
Ray Milkey269ffb92014-04-03 14:43:30 -0700223 bgpdAttachmentPoint = new SwitchPort(
224 new Dpid(config.getBgpdAttachmentDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700225 new PortNumber(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700226
Ray Milkey269ffb92014-04-03 14:43:30 -0700227 bgpdMacAddress = config.getBgpdMacAddress();
228 vlan = config.getVlan();
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -0700229 } catch (JsonParseException | JsonMappingException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700230 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700231 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 } catch (IOException e) {
233 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700234 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700235 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700236
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700237 // Populate the interface Patricia Tree
Ray Milkey269ffb92014-04-03 14:43:30 -0700238 for (Interface intf : interfaces.values()) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700239 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
240 intf.getPrefixLength());
241 interfaceRoutes.put(prefix.toBinaryString(), intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700242 }
243 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700244
Ray Milkey269ffb92014-04-03 14:43:30 -0700245 @Override
246 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
247 Collection<Class<? extends IFloodlightService>> l
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700248 = new ArrayList<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700249 l.add(ISdnIpService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700250 l.add(IConfigInfoService.class);
251 return l;
252 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700253
Ray Milkey269ffb92014-04-03 14:43:30 -0700254 @Override
255 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
256 Map<Class<? extends IFloodlightService>, IFloodlightService> m
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700257 = 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() {
265 Collection<Class<? extends IFloodlightService>> l
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700266 = new ArrayList<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700267 l.add(IFloodlightProviderService.class);
268 l.add(IRestApiService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700269 l.add(IControllerRegistryService.class);
270 l.add(IPathCalcRuntimeService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700271 return l;
272 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700273
Ray Milkey269ffb92014-04-03 14:43:30 -0700274 @Override
275 public void init(FloodlightModuleContext context)
276 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700277
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700278 bgpRoutes = new ConcurrentInvertedRadixTree<>(
279 new DefaultByteArrayNodeFactory());
280 interfaceRoutes = new ConcurrentInvertedRadixTree<>(
281 new DefaultByteArrayNodeFactory());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700282
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700283 ribUpdates = new LinkedBlockingQueue<>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700284
Ray Milkey269ffb92014-04-03 14:43:30 -0700285 // Register floodlight provider and REST handler.
286 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
287 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
288 restApi = context.getServiceImpl(IRestApiService.class);
289 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800290
Komal Shah399a2922014-05-28 01:57:40 -0700291 controllerRegistryService = context.getServiceImpl(IControllerRegistryService.class);
292 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700293
294 //ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
295 //topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700296
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700297 pathsWaitingOnArp = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700298 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
299 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700300
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700301 pushedPaths = new HashMap<>();
302 prefixToPath = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700303// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700304 pushedFlowIds = HashMultimap.create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700305
Ray Milkey269ffb92014-04-03 14:43:30 -0700306 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700307
Ray Milkey269ffb92014-04-03 14:43:30 -0700308 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
309 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700310
Jonathan Hart938a0152014-04-07 18:27:31 -0700311 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700312 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
313 if (bgpdRestIp == null) {
314 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700315 throw new ConfigurationRuntimeException(
316 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700317 } else {
318 log.info("BgpdRestIp set to {}", bgpdRestIp);
319 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700320
Ray Milkey269ffb92014-04-03 14:43:30 -0700321 routerId = context.getConfigParams(this).get("RouterId");
322 if (routerId == null) {
323 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700324 throw new ConfigurationRuntimeException(
325 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700326 } else {
327 log.info("RouterId set to {}", routerId);
328 }
pingping-linba5c52f2014-02-11 16:52:01 -0800329
Ray Milkey269ffb92014-04-03 14:43:30 -0700330 String configFilenameParameter = context.getConfigParams(this).get("configfile");
331 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700332 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700333 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700334 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700335
Ray Milkey5df613b2014-04-15 10:50:56 -0700336 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700337 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700338
Ray Milkey269ffb92014-04-03 14:43:30 -0700339 @Override
340 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700341 restApi.addRestletRoutable(new SdnIpWebRoutable());
Komal Shah399a2922014-05-28 01:57:40 -0700342 restApi.addRestletRoutable(new SdnIpWebRoutableNew());
Ray Milkey269ffb92014-04-03 14:43:30 -0700343 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800344
Jonathan Hart938a0152014-04-07 18:27:31 -0700345 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700346 retrieveRib();
347 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800348
Ray Milkey269ffb92014-04-03 14:43:30 -0700349 @Override
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700350 public RadixTree<RibEntry> getPtree() {
351 return bgpRoutes;
Ray Milkey269ffb92014-04-03 14:43:30 -0700352 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700353
Ray Milkey269ffb92014-04-03 14:43:30 -0700354 @Override
355 public void clearPtree() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700356 log.warn("Clear table operation not supported");
Ray Milkey269ffb92014-04-03 14:43:30 -0700357 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700358
Ray Milkey269ffb92014-04-03 14:43:30 -0700359 @Override
Jonathan Hart31e15f12014-04-10 10:33:00 -0700360 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700361 return bgpdRestIp;
362 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700363
Ray Milkey269ffb92014-04-03 14:43:30 -0700364 @Override
365 public String getRouterId() {
366 return routerId;
367 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700368
Ray Milkey269ffb92014-04-03 14:43:30 -0700369 private void retrieveRib() {
370 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
371 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700372
Jonathan Hart938a0152014-04-07 18:27:31 -0700373 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700374 return;
375 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700376
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700377 try {
378 response = response.replaceAll("\"", "'");
379 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
380 JSONArray ribArray = jsonObj.getJSONArray("rib");
381 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700382
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700383 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700384
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700385 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700386
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700387 for (int j = 0; j < size; j++) {
388 JSONObject ribEntry = ribArray.getJSONObject(j);
389 String prefix = ribEntry.getString("prefix");
390 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700391
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700392 // Insert each rib entry into the local rib
393 String[] substring = prefix.split("/");
394 String prefix1 = substring[0];
395 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700396
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700397 Prefix p;
398 try {
399 p = new Prefix(prefix1, Integer.parseInt(mask1));
400 } catch (NumberFormatException e) {
401 log.warn("Wrong mask format in RIB JSON: {}", mask1);
402 continue;
403 } catch (IllegalArgumentException e1) {
404 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
405 continue;
406 }
407
408 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
409
410 try {
411 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
412 } catch (InterruptedException e) {
413 log.debug("Interrupted while pushing onto update queue");
414 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700415 }
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700416 } catch (JSONException e) {
417 // TODO don't parse JSON manually
418 log.error("Error parsing inital route table JSON:", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700419 }
420 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700421
Ray Milkey269ffb92014-04-03 14:43:30 -0700422 @Override
423 public void newRibUpdate(RibUpdate update) {
424 try {
425 ribUpdates.put(update);
426 } catch (InterruptedException e) {
427 log.debug("Interrupted while putting on ribUpdates queue", e);
428 Thread.currentThread().interrupt();
429 }
430 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700431
Jonathan Hart938a0152014-04-07 18:27:31 -0700432 public void processRibAdd(RibUpdate update) {
433 synchronized (this) {
434 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700435
Jonathan Hart938a0152014-04-07 18:27:31 -0700436 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700437
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700438 RibEntry rib = bgpRoutes.put(prefix.toBinaryString(), update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700439
Jonathan Hart938a0152014-04-07 18:27:31 -0700440 if (rib != null && !rib.equals(update.getRibEntry())) {
441 // There was an existing nexthop for this prefix. This update supersedes that,
442 // so we need to remove the old flows for this prefix from the switches
Ray Milkey7531a342014-04-11 15:08:12 -0700443 executeDeletePrefix(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700444 }
Ray Milkey5d406012014-04-08 14:44:41 -0700445
Jonathan Hart938a0152014-04-07 18:27:31 -0700446 if (update.getRibEntry().getNextHop().equals(
447 InetAddresses.forString("0.0.0.0"))) {
448 // Route originated by SDN domain
449 // We don't handle these at the moment
450 log.debug("Own route {} to {}", prefix,
451 update.getRibEntry().getNextHop().getHostAddress());
452 return;
453 }
Ray Milkey5d406012014-04-08 14:44:41 -0700454
Ray Milkey7531a342014-04-11 15:08:12 -0700455 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700456 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700457 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700458
Ray Milkey7531a342014-04-11 15:08:12 -0700459 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700460 // TODO: Fix the code below. Note that "deviceStorage" was removed.
461
462 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700463 Prefix prefix = update.getPrefix();
464 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700465
Ray Milkey269ffb92014-04-03 14:43:30 -0700466 InetAddress dstIpAddress = rib.getNextHop();
467 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800468
Ray Milkey269ffb92014-04-03 14:43:30 -0700469 // See if we know the MAC address of the next hop
470 // 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 -0700471 IDeviceObject nextHopDevice =
472 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700473
Ray Milkey269ffb92014-04-03 14:43:30 -0700474 if (nextHopDevice == null){
475 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
476 prefixesWaitingOnArp.put(dstIpAddress,
477 new RibUpdate(Operation.UPDATE, prefix, rib));
478 proxyArp.sendArpRequest(dstIpAddress, this, true);
479 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800480
Ray Milkey269ffb92014-04-03 14:43:30 -0700481 }
482 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700483
Ray Milkey269ffb92014-04-03 14:43:30 -0700484 // Find the attachment point (egress interface) of the next hop
485 Interface egressInterface = null;
486 if (bgpPeers.containsKey(dstIpAddress)) {
487 //Route to a peer
488 log.debug("Route to peer {}", dstIpAddress);
489 BgpPeer peer = bgpPeers.get(dstIpAddress);
490 egressInterface = interfaces.get(peer.getInterfaceName());
491 } else {
492 //Route to non-peer
493 log.debug("Route to non-peer {}", dstIpAddress);
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700494 egressInterface = interfacePtree.match(
Ray Milkey269ffb92014-04-03 14:43:30 -0700495 new Prefix(dstIpAddress.getAddress(), 32));
496 if (egressInterface == null) {
497 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
498 return;
499 }
500 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700501
Ray Milkey269ffb92014-04-03 14:43:30 -0700502 if (nextHopMacAddress == null) {
503 prefixesWaitingOnArp.put(dstIpAddress,
504 new RibUpdate(Operation.UPDATE, prefix, rib));
505 proxyArp.sendArpRequest(dstIpAddress, this, true);
506 return;
507 } else {
508 if (!bgpPeers.containsKey(dstIpAddress)) {
509 //If the prefix is for a non-peer we need to ensure there's a path,
510 //and push one if there isn't.
511 Path path = pushedPaths.get(dstIpAddress);
512 if (path == null) {
513 path = new Path(egressInterface, dstIpAddress);
514 calculateAndPushPath(path, nextHopMacAddress);
515 pushedPaths.put(dstIpAddress, path);
516 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700517
Ray Milkey269ffb92014-04-03 14:43:30 -0700518 path.incrementUsers();
519 prefixToPath.put(prefix, path);
520 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700521
Ray Milkey269ffb92014-04-03 14:43:30 -0700522 //For all prefixes we need to add the first-hop mac-rewriting flows
523 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
524 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700525 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700526 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700527
Ray Milkey269ffb92014-04-03 14:43:30 -0700528 /**
529 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
Ray Milkeyb41100a2014-04-10 10:42:15 -0700530 * to all other border switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700531 */
532 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
533 MACAddress nextHopMacAddress) {
534 log.debug("Adding flows for prefix {}, next hop mac {}",
535 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700536
Ray Milkey269ffb92014-04-03 14:43:30 -0700537 FlowPath flowPath = new FlowPath();
538 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700539
Ray Milkey269ffb92014-04-03 14:43:30 -0700540 // Set flowPath FlowPathType and FlowPathUserState
541 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
542 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800543
Ray Milkey269ffb92014-04-03 14:43:30 -0700544 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
545 // only to the first-host switches
546 FlowPathFlags flowPathFlags = new FlowPathFlags();
547 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
548 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800549
Ray Milkey269ffb92014-04-03 14:43:30 -0700550 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700551 SwitchPort dstPort =
552 new SwitchPort(new Dpid(egressInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700553 new PortNumber(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800554
Ray Milkey269ffb92014-04-03 14:43:30 -0700555 // We only need one flow mod per switch, so pick one interface on each switch
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700556 Map<Long, Interface> srcInterfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700557 for (Interface intf : interfaces.values()) {
558 if (!srcInterfaces.containsKey(intf.getDpid())
559 && !intf.equals(egressInterface)) {
560 srcInterfaces.put(intf.getDpid(), intf);
561 }
562 }
563 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800564
Ray Milkey269ffb92014-04-03 14:43:30 -0700565 if (egressInterface.equals(srcInterface)) {
566 continue;
567 }
pingping-linba5c52f2014-02-11 16:52:01 -0800568
Ray Milkey269ffb92014-04-03 14:43:30 -0700569 // Create flowPath FlowId
570 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800571
Ray Milkey269ffb92014-04-03 14:43:30 -0700572 // Create DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700573 SwitchPort srcPort =
574 new SwitchPort(new Dpid(srcInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700575 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800576
Ray Milkey269ffb92014-04-03 14:43:30 -0700577 DataPath dataPath = new DataPath();
578 dataPath.setSrcPort(srcPort);
579 dataPath.setDstPort(dstPort);
580 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800581
Ray Milkey269ffb92014-04-03 14:43:30 -0700582 // Create flow path matching condition(s): IPv4 Prefix
583 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700584 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700585 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
586 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
587 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300588
Ray Milkey269ffb92014-04-03 14:43:30 -0700589 /*
590 * Create the Flow Entry Action(s): dst-MAC rewrite action
591 */
592 FlowEntryActions flowEntryActions = new FlowEntryActions();
593 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
594 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
595 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
596 flowEntryActions.addAction(flowEntryAction1);
597 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800598
Ray Milkey269ffb92014-04-03 14:43:30 -0700599 // Flow Path installation, only to first hop switches
600 // TODO: Add the flow by using the new Path Intent framework
601 /*
602 if (flowManagerService.addFlow(flowPath) == null) {
603 log.error("Failed to install flow path to the first hop for " +
604 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
605 nextHopMacAddress);
606 }
607 else {
608 log.debug("Successfully installed flow path to the first hop " +
609 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
610 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800611
Ray Milkey269ffb92014-04-03 14:43:30 -0700612 pushedFlowIds.put(prefix, flowPath.flowId());
613 }
614 */
615 }
616 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700617
Jonathan Hart938a0152014-04-07 18:27:31 -0700618 public void processRibDelete(RibUpdate update) {
619 synchronized (this) {
620 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700621
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700622 //if (ptree.remove(prefix, update.getRibEntry())) {
623 // TODO check the change of logic here - remove doesn't check that the
624 // rib entry was what we expected (and we can't do this concurrently)
625 if (bgpRoutes.remove(prefix.toBinaryString())) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700626 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700627 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700628 * If no entry was removed, the <prefix, nexthop> wasn't there so
629 * it's probably already been removed and we don't need to do anything
630 */
Ray Milkey7531a342014-04-11 15:08:12 -0700631 executeDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart938a0152014-04-07 18:27:31 -0700632 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700633 }
634 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700635
Ray Milkey7531a342014-04-11 15:08:12 -0700636 private void executeDeletePrefix(Prefix prefix, RibEntry ribEntry) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700637 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700638
Ray Milkey269ffb92014-04-03 14:43:30 -0700639 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700640
Ray Milkey269ffb92014-04-03 14:43:30 -0700641 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
642 log.debug("Getting path for route with non-peer nexthop");
643 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700644
Ray Milkey269ffb92014-04-03 14:43:30 -0700645 if (path != null) {
646 //path could be null if we added to the Ptree but didn't push
647 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700648
Ray Milkey269ffb92014-04-03 14:43:30 -0700649 path.decrementUsers();
650 if (path.getUsers() <= 0 && !path.isPermanent()) {
651 deletePath(path);
652 pushedPaths.remove(path.getDstIpAddress());
653 }
654 }
655 }
656 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700657
Ray Milkey269ffb92014-04-03 14:43:30 -0700658 // TODO have not tested this module
659 private void deletePrefixFlows(Prefix prefix) {
660 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700661
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700662 //
663 // TODO: Delete the flow by using the new Path Intent framework
664 // NOTE: During the refactoring of the code below, if obtaining
665 // the values of the removed flowIds is needed, the first
666 // removeAll() statement should be replaced with the second removeAll()
667 // statement.
668 //
669 pushedFlowIds.removeAll(prefix);
670 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700671 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
672 for (FlowId flowId : flowIds) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700673 if (log.isTraceEnabled()) {
674 //Trace the flow status by flowPath in the switch before deleting it
675 log.trace("Pushing a DELETE flow mod to flowPath : {}",
676 flowManagerService.getFlow(flowId).toString());
677 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700678
Ray Milkey269ffb92014-04-03 14:43:30 -0700679 if( flowManagerService.deleteFlow(flowId))
680 {
681 log.debug("Successfully deleted FlowId: {}",flowId);
682 }
683 else
684 {
685 log.debug("Failed to delete FlowId: {}",flowId);
686 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700687 }
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700688 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700689 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700690
Ray Milkey269ffb92014-04-03 14:43:30 -0700691 // TODO need to record the path and then delete here
692 private void deletePath(Path path) {
693 log.debug("Deleting flows for path to {}",
694 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700695
Ray Milkey269ffb92014-04-03 14:43:30 -0700696 // TODO need update
697 /*for (PushedFlowMod pfm : path.getFlowMods()) {
698 if (log.isTraceEnabled()) {
699 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
700 new Object[] {HexString.toHexString(pfm.getDpid()),
701 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
702 });
703 }
pingping-linba5c52f2014-02-11 16:52:01 -0800704
Ray Milkey269ffb92014-04-03 14:43:30 -0700705 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
706 }*/
707 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700708
709
Ray Milkey269ffb92014-04-03 14:43:30 -0700710 //TODO test next-hop changes
711 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800712
Ray Milkey269ffb92014-04-03 14:43:30 -0700713 /**
714 * On startup, we need to calculate a full mesh of paths between all gateway
Ray Milkeyb41100a2014-04-10 10:42:15 -0700715 * switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700716 */
717 private void setupFullMesh() {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700718 // TODO: Fix the code below. Note that "deviceStorage" was removed.
719
720 /*
721
Ray Milkey269ffb92014-04-03 14:43:30 -0700722 //For each border router, calculate and install a path from every other
723 //border switch to said border router. However, don't install the entry
724 //in to the first hop switch, as we need to install an entry to rewrite
725 //for each prefix received. This will be done later when prefixes have
726 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700727
Ray Milkey269ffb92014-04-03 14:43:30 -0700728 for (BgpPeer peer : bgpPeers.values()) {
729 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700730
Ray Milkey269ffb92014-04-03 14:43:30 -0700731 //We know there's not already a Path here pushed, because this is
732 //called before all other routing
733 Path path = new Path(peerInterface, peer.getIpAddress());
734 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700735
Ray Milkey269ffb92014-04-03 14:43:30 -0700736 //See if we know the MAC address of the peer. If not we can't
737 //do anything until we learn it
Ray Milkey269ffb92014-04-03 14:43:30 -0700738 MACAddress macAddress = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700739 IDeviceObject nextHopDevice =
740 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800741
Ray Milkey269ffb92014-04-03 14:43:30 -0700742 if(nextHopDevice == null){
743 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
744 //Put in the pending paths list first
745 pathsWaitingOnArp.put(peer.getIpAddress(), path);
746 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
747 continue;
748 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700749
Ray Milkey269ffb92014-04-03 14:43:30 -0700750 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
pingping-linba5c52f2014-02-11 16:52:01 -0800751
Ray Milkey269ffb92014-04-03 14:43:30 -0700752 if (macAddress == null) {
753 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
754 //Put in the pending paths list first
755 pathsWaitingOnArp.put(peer.getIpAddress(), path);
756 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
757 continue;
758 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700759
Ray Milkey269ffb92014-04-03 14:43:30 -0700760 //If we know the MAC, lets go ahead and push the paths to this peer
761 calculateAndPushPath(path, macAddress);
762 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700763 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700764 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700765
Ray Milkey269ffb92014-04-03 14:43:30 -0700766 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
767 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700768
Ray Milkey269ffb92014-04-03 14:43:30 -0700769 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
770 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800771
Ray Milkey269ffb92014-04-03 14:43:30 -0700772 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800773
Ray Milkey269ffb92014-04-03 14:43:30 -0700774 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800775
Ray Milkey269ffb92014-04-03 14:43:30 -0700776 // Set flowPath FlowPathType and FlowPathUserState
777 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
778 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800779
Ray Milkey269ffb92014-04-03 14:43:30 -0700780 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
781 FlowPathFlags flowPathFlags = new FlowPathFlags();
782 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
783 flowPath.setFlowPathFlags(flowPathFlags);
784
785 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700786 SwitchPort dstPort =
787 new SwitchPort(new Dpid(dstInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700788 new PortNumber(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800789
Ray Milkey269ffb92014-04-03 14:43:30 -0700790 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800791
Ray Milkey269ffb92014-04-03 14:43:30 -0700792 if (dstInterface.equals(srcInterface)) {
793 continue;
794 }
pingping-linba5c52f2014-02-11 16:52:01 -0800795
Ray Milkey269ffb92014-04-03 14:43:30 -0700796 // Create flowPath FlowId
797 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800798
Ray Milkey269ffb92014-04-03 14:43:30 -0700799 // Create the DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700800 SwitchPort srcPort =
801 new SwitchPort(new Dpid(srcInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700802 new PortNumber(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800803
Ray Milkey269ffb92014-04-03 14:43:30 -0700804 DataPath dataPath = new DataPath();
805 dataPath.setSrcPort(srcPort);
806 dataPath.setDstPort(dstPort);
807 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800808
Ray Milkey269ffb92014-04-03 14:43:30 -0700809 // Create the Flow Path Match condition(s)
810 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700811 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700812 flowEntryMatch.enableDstMac(dstMacAddress);
813 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800814
Ray Milkey269ffb92014-04-03 14:43:30 -0700815 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
816 // Shortest Path Flow, and is always the last action for the Flow Entries
817 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
818 // TODO: Add the flow by using the new Path Intent framework
819 /*
820 if (flowManagerService.addFlow(flowPath) == null) {
821 log.error("Failed to set up MAC based forwarding path to {}, {}",
822 path.getDstIpAddress().getHostAddress(),dstMacAddress);
823 }
824 else {
825 log.debug("Successfully set up MAC based forwarding path to {}, {}",
826 path.getDstIpAddress().getHostAddress(),dstMacAddress);
827 }
828 */
829 }
830 }
pingping-linba5c52f2014-02-11 16:52:01 -0800831
Komal Shah399a2922014-05-28 01:57:40 -0700832 @Override
833 public void beginRoutingNew() {
834 setupBgpPathsNew();
835
836 //setupFullMesh();
837
838 //Suppress link discovery on external-facing router ports
839
840 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -0700841 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Komal Shah399a2922014-05-28 01:57:40 -0700842 }
843
844 bgpUpdatesExecutor.execute(new Runnable() {
845 @Override
846 public void run() {
847 doUpdatesThread();
848 }
849 });
850 }
851
Ray Milkey269ffb92014-04-03 14:43:30 -0700852 /**
Komal Shah399a2922014-05-28 01:57:40 -0700853 * Setup the Paths to the BGP Daemon.
854 *
855 * Run a loop for all of the bgpPeers
856 * Push flow from BGPd to the peer
857 * Push flow from peer to BGPd
858 * Parameters to pass to the intent are as follows:
859 * String id,
860 * long srcSwitch, long srcPort, long srcMac, int srcIP,
861 * long dstSwitch, long dstPort, long dstMac, int dstIP
862 */
863 private void setupBgpPathsNew() {
864 IntentOperationList operations = new IntentOperationList();
865 for (BgpPeer bgpPeer : bgpPeers.values()) {
866 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
867 //Inet4Address.
868 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
869 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
870 String fwdIntentId = callerId + ":" + controllerRegistryService.getNextUniqueId();
871 String bwdIntentId = callerId + ":" + controllerRegistryService.getNextUniqueId();
872 SwitchPort srcPort =
873 new SwitchPort(bgpdAttachmentPoint.dpid(),
874 bgpdAttachmentPoint.port());
875 SwitchPort dstPort =
876 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700877 new PortNumber(peerInterface.getSwitchPort().port()));
Komal Shah399a2922014-05-28 01:57:40 -0700878 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
879 srcPort.dpid().value(), srcPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, srcIP,
880 dstPort.dpid().value(), dstPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, dstIP);
881 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700882 dstPort.dpid().value(), dstPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, dstIP,
883 srcPort.dpid().value(), srcPort.port().value(), ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700884 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
885 operations.add(operator, fwdIntent);
886 operations.add(operator, bwdIntent);
887 }
888 pathRuntime.executeIntentOperations(operations);
889 }
890
891 /*
Jonathan Hart938a0152014-04-07 18:27:31 -0700892 * Proactively install all BGP traffic paths from BGP host attachment point
Ray Milkeyb41100a2014-04-10 10:42:15 -0700893 * in SDN network to all the virtual gateways to BGP peers in other networks.
Ray Milkey269ffb92014-04-03 14:43:30 -0700894 */
895 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200896
Ray Milkey269ffb92014-04-03 14:43:30 -0700897 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800898
Ray Milkey269ffb92014-04-03 14:43:30 -0700899 FlowPath flowPath = new FlowPath();
900 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800901
Ray Milkey269ffb92014-04-03 14:43:30 -0700902 // Set flowPath FlowPathType and FlowPathUserState
903 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
904 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800905
Ray Milkey269ffb92014-04-03 14:43:30 -0700906 // Install flow paths between BGPd and its peers
907 // There is no need to set the FlowPathFlags
908 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800909
Ray Milkey269ffb92014-04-03 14:43:30 -0700910 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Ray Milkey269ffb92014-04-03 14:43:30 -0700911 // Create the Flow Path Match condition(s)
912 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700913 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
pingping-linba5c52f2014-02-11 16:52:01 -0800914
Ray Milkey269ffb92014-04-03 14:43:30 -0700915 // Match both source address and dest address
916 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress() + "/32");
Komal Shah399a2922014-05-28 01:57:40 -0700917
Ray Milkey269ffb92014-04-03 14:43:30 -0700918 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800919
Ray Milkey269ffb92014-04-03 14:43:30 -0700920 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress().getHostAddress() + "/32");
921 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800922
Ray Milkey269ffb92014-04-03 14:43:30 -0700923 // Match TCP protocol
924 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800925
Ray Milkey269ffb92014-04-03 14:43:30 -0700926 // Match destination TCP port
927 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
928 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800929
Ray Milkey269ffb92014-04-03 14:43:30 -0700930 /**
931 * Create the DataPath: BGP -> BGP peer
932 */
933 // Flow path for src-TCP-port
934 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800935
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700936 SwitchPort srcPort =
937 new SwitchPort(bgpdAttachmentPoint.dpid(),
938 bgpdAttachmentPoint.port());
Ray Milkey269ffb92014-04-03 14:43:30 -0700939 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800940
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700941 SwitchPort dstPort =
942 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700943 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700944 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800945
Ray Milkey269ffb92014-04-03 14:43:30 -0700946 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800947
Ray Milkey269ffb92014-04-03 14:43:30 -0700948 // TODO: Add the flow by using the new Path Intent framework
949 /*
950 if (flowManagerService.addFlow(flowPath) == null) {
951 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
952 bgpPeer.getIpAddress().getHostAddress());
953 }
954 else {
955 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
956 bgpPeer.getIpAddress().getHostAddress());
957 }
958 */
pingping-linba5c52f2014-02-11 16:52:01 -0800959
Ray Milkey269ffb92014-04-03 14:43:30 -0700960 // Disable dst-TCP-port, and set src-TCP-port
961 flowEntryMatch.disableDstTcpUdpPort();
962 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
963 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800964
Ray Milkey269ffb92014-04-03 14:43:30 -0700965 // Create a new FlowId
966 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800967
Ray Milkey269ffb92014-04-03 14:43:30 -0700968 // TODO: Add the flow by using the new Path Intent framework
969 /*
970 if (flowManagerService.addFlow(flowPath) == null) {
971 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
972 bgpPeer.getIpAddress().getHostAddress());
973 }
974 else {
975 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
976 bgpPeer.getIpAddress().getHostAddress());
977 }
978 */
pingping-linba5c52f2014-02-11 16:52:01 -0800979
Ray Milkey269ffb92014-04-03 14:43:30 -0700980 /**
981 * Create the DataPath: BGP <-BGP peer
982 */
983 // Reversed BGP flow path for src-TCP-port
984 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800985
Ray Milkey2476cac2014-04-08 11:03:21 -0700986 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800987
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700988 SwitchPort reverseDstPort =
Komal Shah399a2922014-05-28 01:57:40 -0700989 new SwitchPort(bgpdAttachmentPoint.dpid(),
990 bgpdAttachmentPoint.port());
Ray Milkey2476cac2014-04-08 11:03:21 -0700991 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800992
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700993 SwitchPort reverseSrcPort =
Komal Shah399a2922014-05-28 01:57:40 -0700994 new SwitchPort(new Dpid(peerInterface.getDpid()),
Yuta HIGUCHIfb564502014-06-16 21:29:00 -0700995 new PortNumber(peerInterface.getSwitchPort().port()));
Ray Milkey2476cac2014-04-08 11:03:21 -0700996 reverseDataPath.setSrcPort(reverseSrcPort);
997 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800998
Jonathan Hart938a0152014-04-07 18:27:31 -0700999 // Reverse the dst IP and src IP addresses
Ray Milkey269ffb92014-04-03 14:43:30 -07001000 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
1001 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
1002 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001003
Ray Milkey269ffb92014-04-03 14:43:30 -07001004 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001005
Ray Milkey269ffb92014-04-03 14:43:30 -07001006 // TODO: Add the flow by using the new Path Intent framework
1007 /*
1008 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001009
Ray Milkey269ffb92014-04-03 14:43:30 -07001010 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
1011 bgpPeer.getIpAddress().getHostAddress());
1012 }
1013 else {
1014 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
1015 bgpPeer.getIpAddress().getHostAddress());
1016 }
1017 */
pingping-linba5c52f2014-02-11 16:52:01 -08001018
Ray Milkey269ffb92014-04-03 14:43:30 -07001019 // Reversed BGP flow path for dst-TCP-port
1020 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001021
Ray Milkey269ffb92014-04-03 14:43:30 -07001022 // Disable src-TCP-port, and set the dst-TCP-port
1023 flowEntryMatch.disableSrcTcpUdpPort();
1024 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
1025 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001026
Ray Milkey269ffb92014-04-03 14:43:30 -07001027 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001028
Ray Milkey269ffb92014-04-03 14:43:30 -07001029 // TODO: Add the flow by using the new Path Intent framework
1030 /*
1031 if (flowManagerService.addFlow(flowPath) == null) {
1032 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1033 bgpPeer.getIpAddress().getHostAddress());
1034 }
1035 else {
1036 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
1037 bgpPeer.getIpAddress().getHostAddress());
1038 }
1039 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001040
Ray Milkey269ffb92014-04-03 14:43:30 -07001041 /**
1042 * ICMP paths between BGPd and its peers
1043 */
Jonathan Hart938a0152014-04-07 18:27:31 -07001044 // match ICMP protocol BGP <- Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001045 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001046
Ray Milkey269ffb92014-04-03 14:43:30 -07001047 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
1048 flowEntryMatch.disableSrcTcpUdpPort();
1049 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -08001050
Ray Milkey269ffb92014-04-03 14:43:30 -07001051 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001052
Ray Milkey2476cac2014-04-08 11:03:21 -07001053 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001054
Ray Milkey269ffb92014-04-03 14:43:30 -07001055 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001056
Ray Milkey269ffb92014-04-03 14:43:30 -07001057 // TODO: Add the flow by using the new Path Intent framework
1058 /*
1059 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001060
Ray Milkey269ffb92014-04-03 14:43:30 -07001061 log.error("Failed to set up ICMP path BGP <- Peer {}",
1062 bgpPeer.getIpAddress().getHostAddress());
1063 }
1064 else {
1065 log.debug("Successfully set up ICMP path BGP <- Peer {}",
1066 bgpPeer.getIpAddress().getHostAddress());
1067 }
1068 */
pingping-linba5c52f2014-02-11 16:52:01 -08001069
Jonathan Hart938a0152014-04-07 18:27:31 -07001070 // match ICMP protocol BGP -> Peer
Ray Milkey269ffb92014-04-03 14:43:30 -07001071 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -08001072
Ray Milkey269ffb92014-04-03 14:43:30 -07001073 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
1074 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
1075 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -08001076
Ray Milkey269ffb92014-04-03 14:43:30 -07001077 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -08001078
Ray Milkey269ffb92014-04-03 14:43:30 -07001079 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -08001080
Ray Milkey269ffb92014-04-03 14:43:30 -07001081 // TODO: Add the flow by using the new Path Intent framework
1082 /*
1083 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -08001084
Ray Milkey269ffb92014-04-03 14:43:30 -07001085 log.error("Failed to set up ICMP path BGP -> Peer {}",
1086 bgpPeer.getIpAddress().getHostAddress());
1087 }
1088 else {
1089 log.debug("Successfully set up ICMP path BGP -> Peer {}",
1090 bgpPeer.getIpAddress().getHostAddress());
1091 }
1092 */
1093 }
1094 }
pingping-linba5c52f2014-02-11 16:52:01 -08001095
Ray Milkey269ffb92014-04-03 14:43:30 -07001096 @Override
1097 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
1098 log.debug("Received ARP response: {} => {}",
1099 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001100
Ray Milkey269ffb92014-04-03 14:43:30 -07001101 /*
1102 * We synchronize on this to prevent changes to the ptree while we're pushing
1103 * flows to the switches. If the ptree changes, the ptree and switches
1104 * could get out of sync.
1105 */
1106 synchronized (this) {
1107 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001108
Ray Milkey269ffb92014-04-03 14:43:30 -07001109 if (path != null) {
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -07001110 log.debug("Pushing path to {} at {} on {}",
Ray Milkey269ffb92014-04-03 14:43:30 -07001111 path.getDstIpAddress().getHostAddress(), macAddress,
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -07001112 path.getDstInterface().getSwitchPort());
Jonathan Hart938a0152014-04-07 18:27:31 -07001113 // These paths should always be to BGP peers. Paths to non-peers are
1114 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -07001115 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001116 // A path already got pushed to this endpoint while we were waiting
1117 // for ARP. We'll copy over the permanent attribute if it is set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -07001118 if (path.isPermanent()) {
1119 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1120 }
1121 } else {
1122 calculateAndPushPath(path, macAddress);
1123 pushedPaths.put(path.getDstIpAddress(), path);
1124 }
1125 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001126
Ray Milkey269ffb92014-04-03 14:43:30 -07001127 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001128
Ray Milkey269ffb92014-04-03 14:43:30 -07001129 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001130 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001131
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001132 RibEntry rib = bgpRoutes.getValueForExactKey(
1133 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -07001134 if (rib != null && rib.equals(update.getRibEntry())) {
1135 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1136 rib.getNextHop().getHostAddress());
Jonathan Hart938a0152014-04-07 18:27:31 -07001137 // We only push prefix flows if the prefix is still in the ptree
1138 // and the next hop is the same as our update. The prefix could
1139 // have been removed while we were waiting for the ARP, or the
1140 // next hop could have changed.
Ray Milkey7531a342014-04-11 15:08:12 -07001141 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -07001142 } else {
1143 log.debug("Received ARP response, but {},{} is no longer in ptree",
1144 update.getPrefix(), update.getRibEntry());
1145 }
1146 }
1147 }
1148 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001149
Jonathan Hart938a0152014-04-07 18:27:31 -07001150 // TODO wait the priority module of the flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001151 private void setupArpFlows() {
1152 OFMatch match = new OFMatch();
1153 match.setDataLayerType(Ethernet.TYPE_ARP);
1154 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001155
Ray Milkey269ffb92014-04-03 14:43:30 -07001156 OFFlowMod fm = new OFFlowMod();
1157 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001158
Ray Milkey269ffb92014-04-03 14:43:30 -07001159 OFActionOutput action = new OFActionOutput();
1160 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1161 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001162 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -07001163 actions.add(action);
1164 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001165
Ray Milkey269ffb92014-04-03 14:43:30 -07001166 fm.setIdleTimeout((short) 0)
1167 .setHardTimeout((short) 0)
1168 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1169 .setCookie(0)
1170 .setCommand(OFFlowMod.OFPFC_ADD)
1171 .setPriority(ARP_PRIORITY)
1172 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001173
Ray Milkey269ffb92014-04-03 14:43:30 -07001174 for (String strdpid : switches) {
1175 flowCache.write(HexString.toLong(strdpid), fm);
1176 }
1177 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001178
Jonathan Hart938a0152014-04-07 18:27:31 -07001179 // TODO need update, waiting for the priority feature from flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001180 private void setupDefaultDropFlows() {
1181 OFFlowMod fm = new OFFlowMod();
1182 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -07001183 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001184
Ray Milkey269ffb92014-04-03 14:43:30 -07001185 fm.setIdleTimeout((short) 0)
1186 .setHardTimeout((short) 0)
1187 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1188 .setCookie(0)
1189 .setCommand(OFFlowMod.OFPFC_ADD)
1190 .setPriority((short) 0)
1191 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001192
Ray Milkey269ffb92014-04-03 14:43:30 -07001193 OFFlowMod fmLLDP;
1194 OFFlowMod fmBDDP;
1195 try {
1196 fmLLDP = fm.clone();
1197 fmBDDP = fm.clone();
1198 } catch (CloneNotSupportedException e1) {
1199 log.error("Error cloning flow mod", e1);
1200 return;
1201 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001202
Ray Milkey269ffb92014-04-03 14:43:30 -07001203 OFMatch matchLLDP = new OFMatch();
1204 matchLLDP.setDataLayerType((short) 0x88cc);
1205 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1206 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001207
Ray Milkey269ffb92014-04-03 14:43:30 -07001208 OFMatch matchBDDP = new OFMatch();
1209 matchBDDP.setDataLayerType((short) 0x8942);
1210 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1211 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001212
Ray Milkey269ffb92014-04-03 14:43:30 -07001213 OFActionOutput action = new OFActionOutput();
1214 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1215 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001216 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -07001217 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001218
Ray Milkey269ffb92014-04-03 14:43:30 -07001219 fmLLDP.setActions(actions);
1220 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001221
Ray Milkey269ffb92014-04-03 14:43:30 -07001222 fmLLDP.setPriority(ARP_PRIORITY);
1223 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1224 fmBDDP.setPriority(ARP_PRIORITY);
1225 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001226
Sho SHIMIZU84a72de2014-07-09 07:56:40 -07001227 List<OFFlowMod> flowModList = new ArrayList<>(3);
Ray Milkey269ffb92014-04-03 14:43:30 -07001228 flowModList.add(fm);
1229 flowModList.add(fmLLDP);
1230 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001231
Ray Milkey269ffb92014-04-03 14:43:30 -07001232 for (String strdpid : switches) {
1233 flowCache.write(HexString.toLong(strdpid), flowModList);
1234 }
1235 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001236
Ray Milkey269ffb92014-04-03 14:43:30 -07001237 private void beginRouting() {
1238 log.debug("Topology is now ready, beginning routing function");
1239 // TODO: Fix for the new Topology Network Graph
1240 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001241
Ray Milkey269ffb92014-04-03 14:43:30 -07001242 // Wait Pavlin's API. We need the following functions.
1243 /*setupArpFlows();
1244 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001245
Ray Milkey269ffb92014-04-03 14:43:30 -07001246 setupBgpPaths();
1247 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001248
Ray Milkey269ffb92014-04-03 14:43:30 -07001249 //Suppress link discovery on external-facing router ports
1250 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -07001251 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001252 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001253
Ray Milkey269ffb92014-04-03 14:43:30 -07001254 bgpUpdatesExecutor.execute(new Runnable() {
1255 @Override
1256 public void run() {
1257 doUpdatesThread();
1258 }
1259 });
1260 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001261
Jonathan Hart938a0152014-04-07 18:27:31 -07001262 // Before inserting the paths for BGP traffic, we should check whether
1263 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001264 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001265 // TODO: Fix the code below after topoSwitchSerice was removed
1266 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001267 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001268
Ray Milkey269ffb92014-04-03 14:43:30 -07001269 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1270 getActiveSwitches().iterator();
1271 while(activeSwitches.hasNext())
1272 {
1273 ISwitchObject switchObject = activeSwitches.next();
1274 if (switchObject.getDPID().equals(dpid)) {
1275 break;
1276 }
1277 if(activeSwitches.hasNext() == false) {
1278 log.debug("Not all switches are here yet");
1279 return;
1280 }
1281 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001282 }
1283 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001284 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001285 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001286
Jonathan Hart938a0152014-04-07 18:27:31 -07001287 // Actually we only need to go half way round to verify full mesh connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001288 private void checkTopologyReady() {
1289 for (Interface dstInterface : interfaces.values()) {
1290 for (Interface srcInterface : interfaces.values()) {
1291 if (dstInterface.equals(srcInterface)) {
1292 continue;
1293 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001294
Ray Milkey269ffb92014-04-03 14:43:30 -07001295 // TODO: Fix for the new Topology Network Graph
1296 /*
1297 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1298 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001299
Ray Milkey269ffb92014-04-03 14:43:30 -07001300 if (shortestPath == null){
1301 log.debug("Shortest path between {} and {} not found",
1302 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1303 return;
1304 }
1305 */
1306 }
1307 }
1308 topologyReady = true;
1309 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001310
Ray Milkey269ffb92014-04-03 14:43:30 -07001311 private void checkStatus() {
1312 if (!switchesConnected) {
1313 checkSwitchesConnected();
1314 }
1315 boolean oldTopologyReadyStatus = topologyReady;
1316 if (switchesConnected && !topologyReady) {
1317 checkTopologyReady();
1318 }
1319 if (!oldTopologyReadyStatus && topologyReady) {
1320 beginRouting();
1321 }
1322 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001323
Ray Milkey269ffb92014-04-03 14:43:30 -07001324 private void doUpdatesThread() {
1325 boolean interrupted = false;
1326 try {
1327 while (true) {
1328 try {
1329 RibUpdate update = ribUpdates.take();
1330 switch (update.getOperation()) {
1331 case UPDATE:
1332 if (validateUpdate(update)) {
1333 processRibAdd(update);
1334 } else {
1335 log.debug("Rib UPDATE out of order: {} via {}",
1336 update.getPrefix(), update.getRibEntry().getNextHop());
1337 }
1338 break;
1339 case DELETE:
1340 if (validateUpdate(update)) {
1341 processRibDelete(update);
1342 } else {
1343 log.debug("Rib DELETE out of order: {} via {}",
1344 update.getPrefix(), update.getRibEntry().getNextHop());
1345 }
1346 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -07001347 default:
1348 log.error("Unknown operation {}", update.getOperation());
1349 break;
Ray Milkey269ffb92014-04-03 14:43:30 -07001350 }
1351 } catch (InterruptedException e) {
1352 log.debug("Interrupted while taking from updates queue", e);
1353 interrupted = true;
1354 } catch (Exception e) {
1355 log.debug("exception", e);
1356 }
1357 }
1358 } finally {
1359 if (interrupted) {
1360 Thread.currentThread().interrupt();
1361 }
1362 }
1363 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001364
Ray Milkey269ffb92014-04-03 14:43:30 -07001365 private boolean validateUpdate(RibUpdate update) {
1366 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001367 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
1368 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001369
Ray Milkey269ffb92014-04-03 14:43:30 -07001370 //If there is no existing entry we must assume this is the most recent
1371 //update. However this might not always be the case as we might have a
1372 //POST then DELETE reordering.
1373 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1374 if (oldEntry == null) {
1375 return true;
1376 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001377
Ray Milkey269ffb92014-04-03 14:43:30 -07001378 // This handles the case where routes are gathered in the initial
1379 // request because they don't have sequence number info
1380 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1381 return true;
1382 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001383
Ray Milkey269ffb92014-04-03 14:43:30 -07001384 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1385 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001386 }
Ray Milkey4985f212014-04-10 16:57:05 -07001387
1388 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
1389 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -07001390 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001391
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001392 private Interface longestInterfacePrefixMatch(InetAddress address) {
1393 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
1394 Prefix.MAX_PREFIX_LENGTH);
1395 Iterator<Interface> it =
1396 interfaceRoutes.getValuesForKeysPrefixing(
1397 prefixToSearchFor.toBinaryString()).iterator();
1398 Interface intf = null;
1399 // Find the last prefix, which will be the longest prefix
1400 while (it.hasNext()) {
1401 intf = it.next();
1402 }
1403
1404 return intf;
1405 }
1406
Ray Milkey269ffb92014-04-03 14:43:30 -07001407 // The code below should be reimplemented after removal of Floodlight's
1408 // ITopologyService API. It should be implemented on top of network graph
1409 // notifications. (It was pretty hacky anyway...)
1410 /*
1411 @Override
1412 public void topologyChanged() {
1413 if (topologyReady) {
1414 return;
1415 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001416
Ray Milkey269ffb92014-04-03 14:43:30 -07001417 boolean refreshNeeded = false;
1418 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1419 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1420 //We don't need to recalculate anything for just link updates
1421 //They happen very frequently
1422 refreshNeeded = true;
1423 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001424
Ray Milkey269ffb92014-04-03 14:43:30 -07001425 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001426
Ray Milkey269ffb92014-04-03 14:43:30 -07001427 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1428 synchronized (linkUpdates) {
1429 linkUpdates.add(ldu);
1430 }
1431 }
1432 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001433
Ray Milkey269ffb92014-04-03 14:43:30 -07001434 if (refreshNeeded && !topologyReady){
1435 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1436 }
1437 }
1438 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001439
Ray Milkey269ffb92014-04-03 14:43:30 -07001440 @Override
1441 public void addedSwitch(IOFSwitch sw) {
1442 if (!topologyReady) {
1443 sw.clearAllFlowMods();
1444 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001445
Ray Milkey269ffb92014-04-03 14:43:30 -07001446 flowCache.switchConnected(sw);
1447 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001448
Ray Milkey269ffb92014-04-03 14:43:30 -07001449 @Override
1450 public void removedSwitch(IOFSwitch sw) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001451 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001452 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001453
Ray Milkey269ffb92014-04-03 14:43:30 -07001454 @Override
1455 public void switchPortChanged(Long switchId) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001456 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001457 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001458
Ray Milkey269ffb92014-04-03 14:43:30 -07001459 @Override
1460 public String getName() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001461 return "sdnip";
Ray Milkey269ffb92014-04-03 14:43:30 -07001462 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001463
Ray Milkey269ffb92014-04-03 14:43:30 -07001464 /*
1465 * IConfigInfoService methods
1466 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001467
Ray Milkey269ffb92014-04-03 14:43:30 -07001468 @Override
1469 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001470 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001471 return (intf != null && intf.getIpAddress().equals(address));
1472 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001473
Ray Milkey269ffb92014-04-03 14:43:30 -07001474 @Override
1475 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001476 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001477 return (intf != null && !intf.getIpAddress().equals(address));
1478 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001479
Ray Milkey269ffb92014-04-03 14:43:30 -07001480 @Override
1481 public boolean fromExternalNetwork(long inDpid, short inPort) {
1482 for (Interface intf : interfaces.values()) {
1483 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1484 return true;
1485 }
1486 }
1487 return false;
1488 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001489
Ray Milkey269ffb92014-04-03 14:43:30 -07001490 @Override
1491 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001492 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -07001493 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001494
Ray Milkey269ffb92014-04-03 14:43:30 -07001495 @Override
1496 public boolean hasLayer3Configuration() {
1497 return !interfaces.isEmpty();
1498 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001499
Ray Milkey269ffb92014-04-03 14:43:30 -07001500 @Override
1501 public MACAddress getRouterMacAddress() {
1502 return bgpdMacAddress;
1503 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001504
Ray Milkey269ffb92014-04-03 14:43:30 -07001505 @Override
1506 public short getVlan() {
1507 return vlan;
1508 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001509}