blob: ed70ae4b76960e1f449c14aee55966efd2e62d1f [file] [log] [blame]
Jonathan Hart382623d2014-04-03 09:48:11 -07001package net.onrc.onos.apps.bgproute;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
Jonathan Hartd1f23252013-06-13 15:17:05 +12003import java.io.File;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07004import java.io.IOException;
5import java.net.InetAddress;
pingping-lina2cbfad2013-03-07 08:39:21 +08006import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07007import java.util.Collection;
pingping-lina2cbfad2013-03-07 08:39:21 +08008import java.util.HashMap;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07009import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070010import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120011import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120012import java.util.concurrent.BlockingQueue;
13import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120014import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120015import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120016import java.util.concurrent.ScheduledExecutorService;
17import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080018
Jonathan Hart61ba9372013-05-19 20:10:29 -070019import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070020import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart64c0b202013-08-20 15:45:07 +120021import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080022import net.floodlightcontroller.core.module.FloodlightModuleContext;
23import net.floodlightcontroller.core.module.FloodlightModuleException;
24import net.floodlightcontroller.core.module.IFloodlightModule;
25import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120026import net.floodlightcontroller.core.util.SingletonTask;
pingping-lina2cbfad2013-03-07 08:39:21 +080027import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120028import net.floodlightcontroller.util.MACAddress;
Jonathan Hart382623d2014-04-03 09:48:11 -070029import net.onrc.onos.apps.bgproute.RibUpdate.Operation;
Jonathan Hart0961fe82014-04-03 09:56:25 -070030import net.onrc.onos.apps.proxyarp.IArpRequester;
31import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart23701d12014-04-03 10:45:48 -070032import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harta99ec672014-04-03 11:30:34 -070033import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070034import net.onrc.onos.core.main.config.IConfigInfoService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070035import net.onrc.onos.core.packet.Ethernet;
36import net.onrc.onos.core.packet.IPv4;
Jonathan Hart23701d12014-04-03 10:45:48 -070037import net.onrc.onos.core.util.CallerId;
38import net.onrc.onos.core.util.DataPath;
39import net.onrc.onos.core.util.Dpid;
40import net.onrc.onos.core.util.FlowEntryAction;
41import net.onrc.onos.core.util.FlowEntryActions;
42import net.onrc.onos.core.util.FlowEntryMatch;
43import net.onrc.onos.core.util.FlowId;
44import net.onrc.onos.core.util.FlowPath;
45import net.onrc.onos.core.util.FlowPathFlags;
46import net.onrc.onos.core.util.FlowPathType;
47import net.onrc.onos.core.util.FlowPathUserState;
48import net.onrc.onos.core.util.IPv4Net;
49import net.onrc.onos.core.util.Port;
50import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080051import net.sf.json.JSONArray;
52import net.sf.json.JSONObject;
53import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080054
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070055import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120056import org.codehaus.jackson.JsonParseException;
57import org.codehaus.jackson.map.JsonMappingException;
58import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070059import org.openflow.protocol.OFFlowMod;
60import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070061import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120062import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070063import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070064import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120065import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080066import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
Jonathan Hart4dfc3652013-08-02 20:22:36 +120069import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120070import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120071import com.google.common.collect.Multimaps;
72import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120073import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120074import com.google.common.util.concurrent.ThreadFactoryBuilder;
75
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070076public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Ray Milkey269ffb92014-04-03 14:43:30 -070077 IArpRequester,
78 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070079
Ray Milkeyec838942014-04-09 11:28:43 -070080 private static final Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080081
Ray Milkey269ffb92014-04-03 14:43:30 -070082 private IFloodlightProviderService floodlightProvider;
83 private ILinkDiscoveryService linkDiscoveryService;
84 private IRestApiService restApi;
85 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070086
Jonathan Hart5e54f2e2014-04-17 13:43:40 -070087 private IPatriciaTree<RibEntry> ptree;
88 private IPatriciaTree<Interface> interfacePtree;
Ray Milkey269ffb92014-04-03 14:43:30 -070089 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070090
Ray Milkey269ffb92014-04-03 14:43:30 -070091 private String bgpdRestIp;
92 private String routerId;
Ray Milkey5df613b2014-04-15 10:50:56 -070093 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
94 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070095
Ray Milkey2476cac2014-04-08 11:03:21 -070096 private static final short ARP_PRIORITY = 20;
Ray Milkey5d406012014-04-08 14:44:41 -070097
Jonathan Hart938a0152014-04-07 18:27:31 -070098 // The fields below are unused after the move to FlowManager.
99 // Remove them if no longer needed.
100 /*
101 // We need to identify our flows somehow, in lieu of an OS-wide mechanism
102 // to hand out cookie IDs to prevent conflicts.
103 private static final long APP_COOKIE = 0xa0000000000000L;
104 // Cookie for flows that do L2 forwarding within SDN domain to egress routers
105 private static final long L2_FWD_COOKIE = APP_COOKIE + 1;
106 // Cookie for flows in ingress switches that rewrite the MAC address
107 private static final long MAC_RW_COOKIE = APP_COOKIE + 2;
108 // Cookie for flows that setup BGP paths
109 private static final long BGP_COOKIE = APP_COOKIE + 3;
110 // Forwarding uses priority 0, and the mac rewrite entries in ingress switches
111 // need to be higher priority than this otherwise the rewrite may not get done
112 private static final short SDNIP_PRIORITY = 10;
113 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700114
Ray Milkey2476cac2014-04-08 11:03:21 -0700115 private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700116
Jonathan Hart938a0152014-04-07 18:27:31 -0700117 private static final int TOPO_DETECTION_WAIT = 2; // seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700118
Jonathan Hart938a0152014-04-07 18:27:31 -0700119 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700120 private List<String> switches;
121 private Map<String, Interface> interfaces;
122 private Map<InetAddress, BgpPeer> bgpPeers;
123 private SwitchPort bgpdAttachmentPoint;
124 private MACAddress bgpdMacAddress;
125 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700126
Jonathan Hart938a0152014-04-07 18:27:31 -0700127 // True when all switches have connected
Ray Milkey269ffb92014-04-03 14:43:30 -0700128 private volatile boolean switchesConnected = false;
Jonathan Hart938a0152014-04-07 18:27:31 -0700129 // True when we have a full mesh of shortest paths between gateways
Ray Milkey269ffb92014-04-03 14:43:30 -0700130 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200131
Jonathan Hart938a0152014-04-07 18:27:31 -0700132 private List<LDUpdate> linkUpdates;
Ray Milkey269ffb92014-04-03 14:43:30 -0700133 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700134
Ray Milkey269ffb92014-04-03 14:43:30 -0700135 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700136
Ray Milkey269ffb92014-04-03 14:43:30 -0700137 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700138
Ray Milkey269ffb92014-04-03 14:43:30 -0700139 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700140
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 private Map<InetAddress, Path> pushedPaths;
142 private Map<Prefix, Path> prefixToPath;
143 // private Multimap<Prefix, PushedFlowMod> pushedFlows;
144 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700145
Ray Milkey269ffb92014-04-03 14:43:30 -0700146 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700147
Ray Milkey269ffb92014-04-03 14:43:30 -0700148 // TODO: Fix for the new Topology Network Graph
149 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700150
Ray Milkey269ffb92014-04-03 14:43:30 -0700151 private class TopologyChangeDetector implements Runnable {
152 @Override
153 public void run() {
154 log.debug("Running topology change detection task");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700155 // TODO: Fix the code below after topoLinkService was removed
156 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700157 synchronized (linkUpdates) {
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700158
Ray Milkey269ffb92014-04-03 14:43:30 -0700159 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700160
Ray Milkey269ffb92014-04-03 14:43:30 -0700161 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700162
Ray Milkey269ffb92014-04-03 14:43:30 -0700163 Iterator<LDUpdate> it = linkUpdates.iterator();
164 while (it.hasNext()){
165 LDUpdate ldu = it.next();
166 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
167 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700168
Ray Milkey269ffb92014-04-03 14:43:30 -0700169 if (activeLinks.contains(l)){
170 it.remove();
171 }
172 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700173 }
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700174 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700175
Ray Milkey269ffb92014-04-03 14:43:30 -0700176 if (!topologyReady) {
177 if (linkUpdates.isEmpty()) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700178 // All updates have been seen in network map.
179 // We can check if topology is ready
Ray Milkey269ffb92014-04-03 14:43:30 -0700180 log.debug("No known changes outstanding. Checking topology now");
181 checkStatus();
182 } else {
Jonathan Hart938a0152014-04-07 18:27:31 -0700183 // We know of some link updates that haven't propagated to the database yet
Ray Milkey269ffb92014-04-03 14:43:30 -0700184 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
185 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
186 }
187 }
188 }
189 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700190
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 private void readConfiguration(String configFilename) {
192 File gatewaysFile = new File(configFilename);
193 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700194
Ray Milkey269ffb92014-04-03 14:43:30 -0700195 try {
196 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700197
Ray Milkey269ffb92014-04-03 14:43:30 -0700198 switches = config.getSwitches();
199 interfaces = new HashMap<String, Interface>();
200 for (Interface intf : config.getInterfaces()) {
201 interfaces.put(intf.getName(), intf);
202 }
203 bgpPeers = new HashMap<InetAddress, BgpPeer>();
204 for (BgpPeer peer : config.getPeers()) {
205 bgpPeers.put(peer.getIpAddress(), peer);
206 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700207
Ray Milkey269ffb92014-04-03 14:43:30 -0700208 bgpdAttachmentPoint = new SwitchPort(
209 new Dpid(config.getBgpdAttachmentDpid()),
210 new Port(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700211
Ray Milkey269ffb92014-04-03 14:43:30 -0700212 bgpdMacAddress = config.getBgpdMacAddress();
213 vlan = config.getVlan();
214 } catch (JsonParseException e) {
215 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700216 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700217 } catch (JsonMappingException e) {
218 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700219 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700220 } catch (IOException e) {
221 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700222 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700223 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700224
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700225 // Populate the interface Patricia Tree
Ray Milkey269ffb92014-04-03 14:43:30 -0700226 for (Interface intf : interfaces.values()) {
227 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700228 interfacePtree.put(prefix, intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700229 }
230 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700231
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 @Override
233 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
234 Collection<Class<? extends IFloodlightService>> l
235 = new ArrayList<Class<? extends IFloodlightService>>();
236 l.add(IBgpRouteService.class);
237 l.add(IConfigInfoService.class);
238 return l;
239 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700240
Ray Milkey269ffb92014-04-03 14:43:30 -0700241 @Override
242 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
243 Map<Class<? extends IFloodlightService>, IFloodlightService> m
244 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
245 m.put(IBgpRouteService.class, this);
246 m.put(IConfigInfoService.class, this);
247 return m;
248 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800249
Ray Milkey269ffb92014-04-03 14:43:30 -0700250 @Override
251 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
252 Collection<Class<? extends IFloodlightService>> l
253 = new ArrayList<Class<? extends IFloodlightService>>();
254 l.add(IFloodlightProviderService.class);
255 l.add(IRestApiService.class);
256 return l;
257 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700258
Ray Milkey269ffb92014-04-03 14:43:30 -0700259 @Override
260 public void init(FloodlightModuleContext context)
261 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700262
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700263 ptree = new PatriciaTree<RibEntry>(32);
264 interfacePtree = new PatriciaTree<Interface>(32);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700265
Ray Milkey269ffb92014-04-03 14:43:30 -0700266 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700267
Ray Milkey269ffb92014-04-03 14:43:30 -0700268 // Register floodlight provider and REST handler.
269 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
270 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
271 restApi = context.getServiceImpl(IRestApiService.class);
272 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800273
Ray Milkey269ffb92014-04-03 14:43:30 -0700274 linkUpdates = new ArrayList<LDUpdate>();
275 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
276 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700277
Ray Milkey269ffb92014-04-03 14:43:30 -0700278 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
279 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
280 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700281
Ray Milkey269ffb92014-04-03 14:43:30 -0700282 pushedPaths = new HashMap<InetAddress, Path>();
283 prefixToPath = new HashMap<Prefix, Path>();
284// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
285 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700286
Ray Milkey269ffb92014-04-03 14:43:30 -0700287 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700288
Ray Milkey269ffb92014-04-03 14:43:30 -0700289 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
290 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700291
Jonathan Hart938a0152014-04-07 18:27:31 -0700292 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700293 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
294 if (bgpdRestIp == null) {
295 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700296 throw new ConfigurationRuntimeException(
297 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700298 } else {
299 log.info("BgpdRestIp set to {}", bgpdRestIp);
300 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700301
Ray Milkey269ffb92014-04-03 14:43:30 -0700302 routerId = context.getConfigParams(this).get("RouterId");
303 if (routerId == null) {
304 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700305 throw new ConfigurationRuntimeException(
306 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700307 } else {
308 log.info("RouterId set to {}", routerId);
309 }
pingping-linba5c52f2014-02-11 16:52:01 -0800310
Ray Milkey269ffb92014-04-03 14:43:30 -0700311 String configFilenameParameter = context.getConfigParams(this).get("configfile");
312 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700313 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700314 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700315 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700316
Ray Milkey5df613b2014-04-15 10:50:56 -0700317 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700318 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700319
Ray Milkey269ffb92014-04-03 14:43:30 -0700320 @Override
321 public void startUp(FloodlightModuleContext context) {
322 restApi.addRestletRoutable(new BgpRouteWebRoutable());
323 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800324
Jonathan Hart938a0152014-04-07 18:27:31 -0700325 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700326 retrieveRib();
327 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800328
Ray Milkey269ffb92014-04-03 14:43:30 -0700329 @Override
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700330 public IPatriciaTree<RibEntry> getPtree() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700331 return ptree;
332 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700333
Ray Milkey269ffb92014-04-03 14:43:30 -0700334 @Override
335 public void clearPtree() {
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700336 ptree = new PatriciaTree<RibEntry>(32);
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
Jonathan Hart31e15f12014-04-10 10:33:00 -0700340 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700341 return bgpdRestIp;
342 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700343
Ray Milkey269ffb92014-04-03 14:43:30 -0700344 @Override
345 public String getRouterId() {
346 return routerId;
347 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700348
Ray Milkey269ffb92014-04-03 14:43:30 -0700349 private void retrieveRib() {
350 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
351 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700352
Jonathan Hart938a0152014-04-07 18:27:31 -0700353 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700354 return;
355 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700356
Ray Milkey269ffb92014-04-03 14:43:30 -0700357 response = response.replaceAll("\"", "'");
358 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
Jonathan Hart938a0152014-04-07 18:27:31 -0700359 JSONArray ribArray = jsonObj.getJSONArray("rib");
Ray Milkey5df613b2014-04-15 10:50:56 -0700360 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700361
Jonathan Hart938a0152014-04-07 18:27:31 -0700362 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700363
Ray Milkey269ffb92014-04-03 14:43:30 -0700364 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700365
Ray Milkey269ffb92014-04-03 14:43:30 -0700366 for (int j = 0; j < size; j++) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700367 JSONObject ribEntry = ribArray.getJSONObject(j);
368 String prefix = ribEntry.getString("prefix");
369 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700370
Jonathan Hart938a0152014-04-07 18:27:31 -0700371 // Insert each rib entry into the local rib
Ray Milkey269ffb92014-04-03 14:43:30 -0700372 String[] substring = prefix.split("/");
373 String prefix1 = substring[0];
374 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700375
Ray Milkey269ffb92014-04-03 14:43:30 -0700376 Prefix p;
377 try {
378 p = new Prefix(prefix1, Integer.valueOf(mask1));
379 } catch (NumberFormatException e) {
380 log.warn("Wrong mask format in RIB JSON: {}", mask1);
381 continue;
382 } catch (IllegalArgumentException e1) {
383 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
384 continue;
385 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700386
Ray Milkey5df613b2014-04-15 10:50:56 -0700387 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700388
Ray Milkey269ffb92014-04-03 14:43:30 -0700389 try {
390 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
391 } catch (InterruptedException e) {
392 log.debug("Interrupted while pushing onto update queue");
393 }
394 }
395 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700396
Ray Milkey269ffb92014-04-03 14:43:30 -0700397 @Override
398 public void newRibUpdate(RibUpdate update) {
399 try {
400 ribUpdates.put(update);
401 } catch (InterruptedException e) {
402 log.debug("Interrupted while putting on ribUpdates queue", e);
403 Thread.currentThread().interrupt();
404 }
405 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700406
Jonathan Hart938a0152014-04-07 18:27:31 -0700407 public void processRibAdd(RibUpdate update) {
408 synchronized (this) {
409 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700410
Jonathan Hart938a0152014-04-07 18:27:31 -0700411 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700412
Jonathan Hart938a0152014-04-07 18:27:31 -0700413 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700414
Jonathan Hart938a0152014-04-07 18:27:31 -0700415 if (rib != null && !rib.equals(update.getRibEntry())) {
416 // There was an existing nexthop for this prefix. This update supersedes that,
417 // so we need to remove the old flows for this prefix from the switches
Ray Milkey7531a342014-04-11 15:08:12 -0700418 executeDeletePrefix(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700419 }
Ray Milkey5d406012014-04-08 14:44:41 -0700420
Jonathan Hart938a0152014-04-07 18:27:31 -0700421 if (update.getRibEntry().getNextHop().equals(
422 InetAddresses.forString("0.0.0.0"))) {
423 // Route originated by SDN domain
424 // We don't handle these at the moment
425 log.debug("Own route {} to {}", prefix,
426 update.getRibEntry().getNextHop().getHostAddress());
427 return;
428 }
Ray Milkey5d406012014-04-08 14:44:41 -0700429
Ray Milkey7531a342014-04-11 15:08:12 -0700430 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700431 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700432 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700433
Ray Milkey7531a342014-04-11 15:08:12 -0700434 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700435 // TODO: Fix the code below. Note that "deviceStorage" was removed.
436
437 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700438 Prefix prefix = update.getPrefix();
439 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700440
Ray Milkey269ffb92014-04-03 14:43:30 -0700441 InetAddress dstIpAddress = rib.getNextHop();
442 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800443
Ray Milkey269ffb92014-04-03 14:43:30 -0700444 // See if we know the MAC address of the next hop
445 // 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 -0700446 IDeviceObject nextHopDevice =
447 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700448
Ray Milkey269ffb92014-04-03 14:43:30 -0700449 if (nextHopDevice == null){
450 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
451 prefixesWaitingOnArp.put(dstIpAddress,
452 new RibUpdate(Operation.UPDATE, prefix, rib));
453 proxyArp.sendArpRequest(dstIpAddress, this, true);
454 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800455
Ray Milkey269ffb92014-04-03 14:43:30 -0700456 }
457 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700458
Ray Milkey269ffb92014-04-03 14:43:30 -0700459 // Find the attachment point (egress interface) of the next hop
460 Interface egressInterface = null;
461 if (bgpPeers.containsKey(dstIpAddress)) {
462 //Route to a peer
463 log.debug("Route to peer {}", dstIpAddress);
464 BgpPeer peer = bgpPeers.get(dstIpAddress);
465 egressInterface = interfaces.get(peer.getInterfaceName());
466 } else {
467 //Route to non-peer
468 log.debug("Route to non-peer {}", dstIpAddress);
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700469 egressInterface = interfacePtree.match(
Ray Milkey269ffb92014-04-03 14:43:30 -0700470 new Prefix(dstIpAddress.getAddress(), 32));
471 if (egressInterface == null) {
472 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
473 return;
474 }
475 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700476
Ray Milkey269ffb92014-04-03 14:43:30 -0700477 if (nextHopMacAddress == null) {
478 prefixesWaitingOnArp.put(dstIpAddress,
479 new RibUpdate(Operation.UPDATE, prefix, rib));
480 proxyArp.sendArpRequest(dstIpAddress, this, true);
481 return;
482 } else {
483 if (!bgpPeers.containsKey(dstIpAddress)) {
484 //If the prefix is for a non-peer we need to ensure there's a path,
485 //and push one if there isn't.
486 Path path = pushedPaths.get(dstIpAddress);
487 if (path == null) {
488 path = new Path(egressInterface, dstIpAddress);
489 calculateAndPushPath(path, nextHopMacAddress);
490 pushedPaths.put(dstIpAddress, path);
491 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700492
Ray Milkey269ffb92014-04-03 14:43:30 -0700493 path.incrementUsers();
494 prefixToPath.put(prefix, path);
495 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700496
Ray Milkey269ffb92014-04-03 14:43:30 -0700497 //For all prefixes we need to add the first-hop mac-rewriting flows
498 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
499 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700500 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700501 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700502
Ray Milkey269ffb92014-04-03 14:43:30 -0700503 /**
504 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
Ray Milkeyb41100a2014-04-10 10:42:15 -0700505 * to all other border switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700506 */
507 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
508 MACAddress nextHopMacAddress) {
509 log.debug("Adding flows for prefix {}, next hop mac {}",
510 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700511
Ray Milkey269ffb92014-04-03 14:43:30 -0700512 FlowPath flowPath = new FlowPath();
513 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700514
Ray Milkey269ffb92014-04-03 14:43:30 -0700515 // Set flowPath FlowPathType and FlowPathUserState
516 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
517 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800518
Ray Milkey269ffb92014-04-03 14:43:30 -0700519 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
520 // only to the first-host switches
521 FlowPathFlags flowPathFlags = new FlowPathFlags();
522 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
523 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800524
Ray Milkey269ffb92014-04-03 14:43:30 -0700525 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700526 SwitchPort dstPort =
527 new SwitchPort(new Dpid(egressInterface.getDpid()),
528 new Port(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800529
Ray Milkey269ffb92014-04-03 14:43:30 -0700530 // We only need one flow mod per switch, so pick one interface on each switch
531 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
532 for (Interface intf : interfaces.values()) {
533 if (!srcInterfaces.containsKey(intf.getDpid())
534 && !intf.equals(egressInterface)) {
535 srcInterfaces.put(intf.getDpid(), intf);
536 }
537 }
538 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800539
Ray Milkey269ffb92014-04-03 14:43:30 -0700540 if (egressInterface.equals(srcInterface)) {
541 continue;
542 }
pingping-linba5c52f2014-02-11 16:52:01 -0800543
Ray Milkey269ffb92014-04-03 14:43:30 -0700544 // Create flowPath FlowId
545 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800546
Ray Milkey269ffb92014-04-03 14:43:30 -0700547 // Create DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700548 SwitchPort srcPort =
549 new SwitchPort(new Dpid(srcInterface.getDpid()),
550 new Port(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800551
Ray Milkey269ffb92014-04-03 14:43:30 -0700552 DataPath dataPath = new DataPath();
553 dataPath.setSrcPort(srcPort);
554 dataPath.setDstPort(dstPort);
555 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800556
Ray Milkey269ffb92014-04-03 14:43:30 -0700557 // Create flow path matching condition(s): IPv4 Prefix
558 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700559 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700560 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
561 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
562 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300563
Ray Milkey269ffb92014-04-03 14:43:30 -0700564 /*
565 * Create the Flow Entry Action(s): dst-MAC rewrite action
566 */
567 FlowEntryActions flowEntryActions = new FlowEntryActions();
568 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
569 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
570 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
571 flowEntryActions.addAction(flowEntryAction1);
572 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800573
Ray Milkey269ffb92014-04-03 14:43:30 -0700574 // Flow Path installation, only to first hop switches
575 // TODO: Add the flow by using the new Path Intent framework
576 /*
577 if (flowManagerService.addFlow(flowPath) == null) {
578 log.error("Failed to install flow path to the first hop for " +
579 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
580 nextHopMacAddress);
581 }
582 else {
583 log.debug("Successfully installed flow path to the first hop " +
584 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
585 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800586
Ray Milkey269ffb92014-04-03 14:43:30 -0700587 pushedFlowIds.put(prefix, flowPath.flowId());
588 }
589 */
590 }
591 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700592
Jonathan Hart938a0152014-04-07 18:27:31 -0700593 public void processRibDelete(RibUpdate update) {
594 synchronized (this) {
595 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700596
Jonathan Hart938a0152014-04-07 18:27:31 -0700597 if (ptree.remove(prefix, update.getRibEntry())) {
598 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700599 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700600 * If no entry was removed, the <prefix, nexthop> wasn't there so
601 * it's probably already been removed and we don't need to do anything
602 */
Ray Milkey7531a342014-04-11 15:08:12 -0700603 executeDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart938a0152014-04-07 18:27:31 -0700604 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700605 }
606 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700607
Ray Milkey7531a342014-04-11 15:08:12 -0700608 private void executeDeletePrefix(Prefix prefix, RibEntry ribEntry) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700609 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700610
Ray Milkey269ffb92014-04-03 14:43:30 -0700611 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700612
Ray Milkey269ffb92014-04-03 14:43:30 -0700613 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
614 log.debug("Getting path for route with non-peer nexthop");
615 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700616
Ray Milkey269ffb92014-04-03 14:43:30 -0700617 if (path != null) {
618 //path could be null if we added to the Ptree but didn't push
619 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700620
Ray Milkey269ffb92014-04-03 14:43:30 -0700621 path.decrementUsers();
622 if (path.getUsers() <= 0 && !path.isPermanent()) {
623 deletePath(path);
624 pushedPaths.remove(path.getDstIpAddress());
625 }
626 }
627 }
628 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700629
Ray Milkey269ffb92014-04-03 14:43:30 -0700630 // TODO have not tested this module
631 private void deletePrefixFlows(Prefix prefix) {
632 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700633
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700634 //
635 // TODO: Delete the flow by using the new Path Intent framework
636 // NOTE: During the refactoring of the code below, if obtaining
637 // the values of the removed flowIds is needed, the first
638 // removeAll() statement should be replaced with the second removeAll()
639 // statement.
640 //
641 pushedFlowIds.removeAll(prefix);
642 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700643 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
644 for (FlowId flowId : flowIds) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700645 if (log.isTraceEnabled()) {
646 //Trace the flow status by flowPath in the switch before deleting it
647 log.trace("Pushing a DELETE flow mod to flowPath : {}",
648 flowManagerService.getFlow(flowId).toString());
649 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700650
Ray Milkey269ffb92014-04-03 14:43:30 -0700651 if( flowManagerService.deleteFlow(flowId))
652 {
653 log.debug("Successfully deleted FlowId: {}",flowId);
654 }
655 else
656 {
657 log.debug("Failed to delete FlowId: {}",flowId);
658 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700659 }
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700660 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700661 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700662
Ray Milkey269ffb92014-04-03 14:43:30 -0700663 // TODO need to record the path and then delete here
664 private void deletePath(Path path) {
665 log.debug("Deleting flows for path to {}",
666 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700667
Ray Milkey269ffb92014-04-03 14:43:30 -0700668 // TODO need update
669 /*for (PushedFlowMod pfm : path.getFlowMods()) {
670 if (log.isTraceEnabled()) {
671 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
672 new Object[] {HexString.toHexString(pfm.getDpid()),
673 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
674 });
675 }
pingping-linba5c52f2014-02-11 16:52:01 -0800676
Ray Milkey269ffb92014-04-03 14:43:30 -0700677 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
678 }*/
679 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700680
681
Ray Milkey269ffb92014-04-03 14:43:30 -0700682 //TODO test next-hop changes
683 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800684
Ray Milkey269ffb92014-04-03 14:43:30 -0700685 /**
686 * On startup, we need to calculate a full mesh of paths between all gateway
Ray Milkeyb41100a2014-04-10 10:42:15 -0700687 * switches.
Ray Milkey269ffb92014-04-03 14:43:30 -0700688 */
689 private void setupFullMesh() {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700690 // TODO: Fix the code below. Note that "deviceStorage" was removed.
691
692 /*
693
Ray Milkey269ffb92014-04-03 14:43:30 -0700694 //For each border router, calculate and install a path from every other
695 //border switch to said border router. However, don't install the entry
696 //in to the first hop switch, as we need to install an entry to rewrite
697 //for each prefix received. This will be done later when prefixes have
698 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700699
Ray Milkey269ffb92014-04-03 14:43:30 -0700700 for (BgpPeer peer : bgpPeers.values()) {
701 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700702
Ray Milkey269ffb92014-04-03 14:43:30 -0700703 //We know there's not already a Path here pushed, because this is
704 //called before all other routing
705 Path path = new Path(peerInterface, peer.getIpAddress());
706 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700707
Ray Milkey269ffb92014-04-03 14:43:30 -0700708 //See if we know the MAC address of the peer. If not we can't
709 //do anything until we learn it
Ray Milkey269ffb92014-04-03 14:43:30 -0700710 MACAddress macAddress = null;
Ray Milkey269ffb92014-04-03 14:43:30 -0700711 IDeviceObject nextHopDevice =
712 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800713
Ray Milkey269ffb92014-04-03 14:43:30 -0700714 if(nextHopDevice == null){
715 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
716 //Put in the pending paths list first
717 pathsWaitingOnArp.put(peer.getIpAddress(), path);
718 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
719 continue;
720 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700721
Ray Milkey269ffb92014-04-03 14:43:30 -0700722 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
pingping-linba5c52f2014-02-11 16:52:01 -0800723
Ray Milkey269ffb92014-04-03 14:43:30 -0700724 if (macAddress == null) {
725 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
726 //Put in the pending paths list first
727 pathsWaitingOnArp.put(peer.getIpAddress(), path);
728 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
729 continue;
730 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700731
Ray Milkey269ffb92014-04-03 14:43:30 -0700732 //If we know the MAC, lets go ahead and push the paths to this peer
733 calculateAndPushPath(path, macAddress);
734 }
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700735 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700736 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700737
Ray Milkey269ffb92014-04-03 14:43:30 -0700738 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
739 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700740
Ray Milkey269ffb92014-04-03 14:43:30 -0700741 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
742 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800743
Ray Milkey269ffb92014-04-03 14:43:30 -0700744 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800745
Ray Milkey269ffb92014-04-03 14:43:30 -0700746 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800747
Ray Milkey269ffb92014-04-03 14:43:30 -0700748 // Set flowPath FlowPathType and FlowPathUserState
749 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
750 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800751
Ray Milkey269ffb92014-04-03 14:43:30 -0700752 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
753 FlowPathFlags flowPathFlags = new FlowPathFlags();
754 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
755 flowPath.setFlowPathFlags(flowPathFlags);
756
757 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700758 SwitchPort dstPort =
759 new SwitchPort(new Dpid(dstInterface.getDpid()),
760 new Port(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800761
Ray Milkey269ffb92014-04-03 14:43:30 -0700762 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800763
Ray Milkey269ffb92014-04-03 14:43:30 -0700764 if (dstInterface.equals(srcInterface)) {
765 continue;
766 }
pingping-linba5c52f2014-02-11 16:52:01 -0800767
Ray Milkey269ffb92014-04-03 14:43:30 -0700768 // Create flowPath FlowId
769 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800770
Ray Milkey269ffb92014-04-03 14:43:30 -0700771 // Create the DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700772 SwitchPort srcPort =
773 new SwitchPort(new Dpid(srcInterface.getDpid()),
774 new Port(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800775
Ray Milkey269ffb92014-04-03 14:43:30 -0700776 DataPath dataPath = new DataPath();
777 dataPath.setSrcPort(srcPort);
778 dataPath.setDstPort(dstPort);
779 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800780
Ray Milkey269ffb92014-04-03 14:43:30 -0700781 // Create the Flow Path Match condition(s)
782 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700783 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700784 flowEntryMatch.enableDstMac(dstMacAddress);
785 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800786
Ray Milkey269ffb92014-04-03 14:43:30 -0700787 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
788 // Shortest Path Flow, and is always the last action for the Flow Entries
789 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
790 // TODO: Add the flow by using the new Path Intent framework
791 /*
792 if (flowManagerService.addFlow(flowPath) == null) {
793 log.error("Failed to set up MAC based forwarding path to {}, {}",
794 path.getDstIpAddress().getHostAddress(),dstMacAddress);
795 }
796 else {
797 log.debug("Successfully set up MAC based forwarding path to {}, {}",
798 path.getDstIpAddress().getHostAddress(),dstMacAddress);
799 }
800 */
801 }
802 }
pingping-linba5c52f2014-02-11 16:52:01 -0800803
Ray Milkey269ffb92014-04-03 14:43:30 -0700804 /**
Jonathan Hart938a0152014-04-07 18:27:31 -0700805 * Proactively install all BGP traffic paths from BGP host attachment point
Ray Milkeyb41100a2014-04-10 10:42:15 -0700806 * in SDN network to all the virtual gateways to BGP peers in other networks.
Ray Milkey269ffb92014-04-03 14:43:30 -0700807 */
808 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200809
Ray Milkey269ffb92014-04-03 14:43:30 -0700810 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800811
Ray Milkey269ffb92014-04-03 14:43:30 -0700812 FlowPath flowPath = new FlowPath();
813 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800814
Ray Milkey269ffb92014-04-03 14:43:30 -0700815 // Set flowPath FlowPathType and FlowPathUserState
816 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
817 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800818
Ray Milkey269ffb92014-04-03 14:43:30 -0700819 // Install flow paths between BGPd and its peers
820 // There is no need to set the FlowPathFlags
821 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800822
Ray Milkey269ffb92014-04-03 14:43:30 -0700823 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
pingping-linba5c52f2014-02-11 16:52:01 -0800824
Ray Milkey269ffb92014-04-03 14:43:30 -0700825 // Create the Flow Path Match condition(s)
826 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700827 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
pingping-linba5c52f2014-02-11 16:52:01 -0800828
Ray Milkey269ffb92014-04-03 14:43:30 -0700829 // Match both source address and dest address
830 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress() + "/32");
831 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800832
Ray Milkey269ffb92014-04-03 14:43:30 -0700833 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress().getHostAddress() + "/32");
834 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800835
Ray Milkey269ffb92014-04-03 14:43:30 -0700836 // Match TCP protocol
837 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800838
Ray Milkey269ffb92014-04-03 14:43:30 -0700839 // Match destination TCP port
840 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
841 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800842
Ray Milkey269ffb92014-04-03 14:43:30 -0700843 /**
844 * Create the DataPath: BGP -> BGP peer
845 */
846 // Flow path for src-TCP-port
847 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800848
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700849 SwitchPort srcPort =
850 new SwitchPort(bgpdAttachmentPoint.dpid(),
851 bgpdAttachmentPoint.port());
Ray Milkey269ffb92014-04-03 14:43:30 -0700852 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800853
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700854 SwitchPort dstPort =
855 new SwitchPort(new Dpid(peerInterface.getDpid()),
856 new Port(peerInterface.getSwitchPort().port()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700857 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800858
Ray Milkey269ffb92014-04-03 14:43:30 -0700859 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800860
Ray Milkey269ffb92014-04-03 14:43:30 -0700861 // TODO: Add the flow by using the new Path Intent framework
862 /*
863 if (flowManagerService.addFlow(flowPath) == null) {
864 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
865 bgpPeer.getIpAddress().getHostAddress());
866 }
867 else {
868 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
869 bgpPeer.getIpAddress().getHostAddress());
870 }
871 */
pingping-linba5c52f2014-02-11 16:52:01 -0800872
Ray Milkey269ffb92014-04-03 14:43:30 -0700873 // Disable dst-TCP-port, and set src-TCP-port
874 flowEntryMatch.disableDstTcpUdpPort();
875 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
876 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800877
Ray Milkey269ffb92014-04-03 14:43:30 -0700878 // Create a new FlowId
879 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800880
Ray Milkey269ffb92014-04-03 14:43:30 -0700881 // TODO: Add the flow by using the new Path Intent framework
882 /*
883 if (flowManagerService.addFlow(flowPath) == null) {
884 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
885 bgpPeer.getIpAddress().getHostAddress());
886 }
887 else {
888 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
889 bgpPeer.getIpAddress().getHostAddress());
890 }
891 */
pingping-linba5c52f2014-02-11 16:52:01 -0800892
Ray Milkey269ffb92014-04-03 14:43:30 -0700893 /**
894 * Create the DataPath: BGP <-BGP peer
895 */
896 // Reversed BGP flow path for src-TCP-port
897 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800898
Ray Milkey2476cac2014-04-08 11:03:21 -0700899 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800900
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700901 SwitchPort reverseDstPort =
902 new SwitchPort(bgpdAttachmentPoint.dpid(),
903 bgpdAttachmentPoint.port());
Ray Milkey2476cac2014-04-08 11:03:21 -0700904 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800905
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700906 SwitchPort reverseSrcPort =
907 new SwitchPort(new Dpid(peerInterface.getDpid()),
908 new Port(peerInterface.getSwitchPort().port()));
Ray Milkey2476cac2014-04-08 11:03:21 -0700909 reverseDataPath.setSrcPort(reverseSrcPort);
910 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800911
Jonathan Hart938a0152014-04-07 18:27:31 -0700912 // Reverse the dst IP and src IP addresses
Ray Milkey269ffb92014-04-03 14:43:30 -0700913 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
914 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
915 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800916
Ray Milkey269ffb92014-04-03 14:43:30 -0700917 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800918
Ray Milkey269ffb92014-04-03 14:43:30 -0700919 // TODO: Add the flow by using the new Path Intent framework
920 /*
921 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800922
Ray Milkey269ffb92014-04-03 14:43:30 -0700923 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
924 bgpPeer.getIpAddress().getHostAddress());
925 }
926 else {
927 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
928 bgpPeer.getIpAddress().getHostAddress());
929 }
930 */
pingping-linba5c52f2014-02-11 16:52:01 -0800931
Ray Milkey269ffb92014-04-03 14:43:30 -0700932 // Reversed BGP flow path for dst-TCP-port
933 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800934
Ray Milkey269ffb92014-04-03 14:43:30 -0700935 // Disable src-TCP-port, and set the dst-TCP-port
936 flowEntryMatch.disableSrcTcpUdpPort();
937 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
938 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800939
Ray Milkey269ffb92014-04-03 14:43:30 -0700940 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800941
Ray Milkey269ffb92014-04-03 14:43:30 -0700942 // TODO: Add the flow by using the new Path Intent framework
943 /*
944 if (flowManagerService.addFlow(flowPath) == null) {
945 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
946 bgpPeer.getIpAddress().getHostAddress());
947 }
948 else {
949 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
950 bgpPeer.getIpAddress().getHostAddress());
951 }
952 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700953
Ray Milkey269ffb92014-04-03 14:43:30 -0700954 /**
955 * ICMP paths between BGPd and its peers
956 */
Jonathan Hart938a0152014-04-07 18:27:31 -0700957 // match ICMP protocol BGP <- Peer
Ray Milkey269ffb92014-04-03 14:43:30 -0700958 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800959
Ray Milkey269ffb92014-04-03 14:43:30 -0700960 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
961 flowEntryMatch.disableSrcTcpUdpPort();
962 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -0800963
Ray Milkey269ffb92014-04-03 14:43:30 -0700964 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800965
Ray Milkey2476cac2014-04-08 11:03:21 -0700966 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800967
Ray Milkey269ffb92014-04-03 14:43:30 -0700968 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800969
Ray Milkey269ffb92014-04-03 14:43:30 -0700970 // TODO: Add the flow by using the new Path Intent framework
971 /*
972 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800973
Ray Milkey269ffb92014-04-03 14:43:30 -0700974 log.error("Failed to set up ICMP path BGP <- Peer {}",
975 bgpPeer.getIpAddress().getHostAddress());
976 }
977 else {
978 log.debug("Successfully set up ICMP path BGP <- Peer {}",
979 bgpPeer.getIpAddress().getHostAddress());
980 }
981 */
pingping-linba5c52f2014-02-11 16:52:01 -0800982
Jonathan Hart938a0152014-04-07 18:27:31 -0700983 // match ICMP protocol BGP -> Peer
Ray Milkey269ffb92014-04-03 14:43:30 -0700984 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800985
Ray Milkey269ffb92014-04-03 14:43:30 -0700986 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
987 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
988 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800989
Ray Milkey269ffb92014-04-03 14:43:30 -0700990 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800991
Ray Milkey269ffb92014-04-03 14:43:30 -0700992 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800993
Ray Milkey269ffb92014-04-03 14:43:30 -0700994 // TODO: Add the flow by using the new Path Intent framework
995 /*
996 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800997
Ray Milkey269ffb92014-04-03 14:43:30 -0700998 log.error("Failed to set up ICMP path BGP -> Peer {}",
999 bgpPeer.getIpAddress().getHostAddress());
1000 }
1001 else {
1002 log.debug("Successfully set up ICMP path BGP -> Peer {}",
1003 bgpPeer.getIpAddress().getHostAddress());
1004 }
1005 */
1006 }
1007 }
pingping-linba5c52f2014-02-11 16:52:01 -08001008
Ray Milkey269ffb92014-04-03 14:43:30 -07001009 @Override
1010 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
1011 log.debug("Received ARP response: {} => {}",
1012 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001013
Ray Milkey269ffb92014-04-03 14:43:30 -07001014 /*
1015 * We synchronize on this to prevent changes to the ptree while we're pushing
1016 * flows to the switches. If the ptree changes, the ptree and switches
1017 * could get out of sync.
1018 */
1019 synchronized (this) {
1020 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001021
Ray Milkey269ffb92014-04-03 14:43:30 -07001022 if (path != null) {
1023 log.debug("Pushing path to {} at {} on {}", new Object[]{
1024 path.getDstIpAddress().getHostAddress(), macAddress,
1025 path.getDstInterface().getSwitchPort()});
Jonathan Hart938a0152014-04-07 18:27:31 -07001026 // These paths should always be to BGP peers. Paths to non-peers are
1027 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -07001028 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001029 // A path already got pushed to this endpoint while we were waiting
1030 // for ARP. We'll copy over the permanent attribute if it is set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -07001031 if (path.isPermanent()) {
1032 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1033 }
1034 } else {
1035 calculateAndPushPath(path, macAddress);
1036 pushedPaths.put(path.getDstIpAddress(), path);
1037 }
1038 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001039
Ray Milkey269ffb92014-04-03 14:43:30 -07001040 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001041
Ray Milkey269ffb92014-04-03 14:43:30 -07001042 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001043 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001044
Ray Milkey269ffb92014-04-03 14:43:30 -07001045 RibEntry rib = ptree.lookup(update.getPrefix());
1046 if (rib != null && rib.equals(update.getRibEntry())) {
1047 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1048 rib.getNextHop().getHostAddress());
Jonathan Hart938a0152014-04-07 18:27:31 -07001049 // We only push prefix flows if the prefix is still in the ptree
1050 // and the next hop is the same as our update. The prefix could
1051 // have been removed while we were waiting for the ARP, or the
1052 // next hop could have changed.
Ray Milkey7531a342014-04-11 15:08:12 -07001053 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -07001054 } else {
1055 log.debug("Received ARP response, but {},{} is no longer in ptree",
1056 update.getPrefix(), update.getRibEntry());
1057 }
1058 }
1059 }
1060 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001061
Jonathan Hart938a0152014-04-07 18:27:31 -07001062 // TODO wait the priority module of the flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001063 private void setupArpFlows() {
1064 OFMatch match = new OFMatch();
1065 match.setDataLayerType(Ethernet.TYPE_ARP);
1066 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001067
Ray Milkey269ffb92014-04-03 14:43:30 -07001068 OFFlowMod fm = new OFFlowMod();
1069 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001070
Ray Milkey269ffb92014-04-03 14:43:30 -07001071 OFActionOutput action = new OFActionOutput();
1072 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1073 action.setMaxLength((short) 0xffff);
1074 List<OFAction> actions = new ArrayList<OFAction>(1);
1075 actions.add(action);
1076 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001077
Ray Milkey269ffb92014-04-03 14:43:30 -07001078 fm.setIdleTimeout((short) 0)
1079 .setHardTimeout((short) 0)
1080 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1081 .setCookie(0)
1082 .setCommand(OFFlowMod.OFPFC_ADD)
1083 .setPriority(ARP_PRIORITY)
1084 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001085
Ray Milkey269ffb92014-04-03 14:43:30 -07001086 for (String strdpid : switches) {
1087 flowCache.write(HexString.toLong(strdpid), fm);
1088 }
1089 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001090
Jonathan Hart938a0152014-04-07 18:27:31 -07001091 // TODO need update, waiting for the priority feature from flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001092 private void setupDefaultDropFlows() {
1093 OFFlowMod fm = new OFFlowMod();
1094 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -07001095 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001096
Ray Milkey269ffb92014-04-03 14:43:30 -07001097 fm.setIdleTimeout((short) 0)
1098 .setHardTimeout((short) 0)
1099 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1100 .setCookie(0)
1101 .setCommand(OFFlowMod.OFPFC_ADD)
1102 .setPriority((short) 0)
1103 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001104
Ray Milkey269ffb92014-04-03 14:43:30 -07001105 OFFlowMod fmLLDP;
1106 OFFlowMod fmBDDP;
1107 try {
1108 fmLLDP = fm.clone();
1109 fmBDDP = fm.clone();
1110 } catch (CloneNotSupportedException e1) {
1111 log.error("Error cloning flow mod", e1);
1112 return;
1113 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001114
Ray Milkey269ffb92014-04-03 14:43:30 -07001115 OFMatch matchLLDP = new OFMatch();
1116 matchLLDP.setDataLayerType((short) 0x88cc);
1117 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1118 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001119
Ray Milkey269ffb92014-04-03 14:43:30 -07001120 OFMatch matchBDDP = new OFMatch();
1121 matchBDDP.setDataLayerType((short) 0x8942);
1122 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1123 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001124
Ray Milkey269ffb92014-04-03 14:43:30 -07001125 OFActionOutput action = new OFActionOutput();
1126 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1127 action.setMaxLength((short) 0xffff);
1128 List<OFAction> actions = new ArrayList<OFAction>(1);
1129 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001130
Ray Milkey269ffb92014-04-03 14:43:30 -07001131 fmLLDP.setActions(actions);
1132 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001133
Ray Milkey269ffb92014-04-03 14:43:30 -07001134 fmLLDP.setPriority(ARP_PRIORITY);
1135 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1136 fmBDDP.setPriority(ARP_PRIORITY);
1137 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001138
Ray Milkey269ffb92014-04-03 14:43:30 -07001139 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1140 flowModList.add(fm);
1141 flowModList.add(fmLLDP);
1142 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001143
Ray Milkey269ffb92014-04-03 14:43:30 -07001144 for (String strdpid : switches) {
1145 flowCache.write(HexString.toLong(strdpid), flowModList);
1146 }
1147 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001148
Ray Milkey269ffb92014-04-03 14:43:30 -07001149 private void beginRouting() {
1150 log.debug("Topology is now ready, beginning routing function");
1151 // TODO: Fix for the new Topology Network Graph
1152 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001153
Ray Milkey269ffb92014-04-03 14:43:30 -07001154 // Wait Pavlin's API. We need the following functions.
1155 /*setupArpFlows();
1156 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001157
Ray Milkey269ffb92014-04-03 14:43:30 -07001158 setupBgpPaths();
1159 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001160
Ray Milkey269ffb92014-04-03 14:43:30 -07001161 //Suppress link discovery on external-facing router ports
1162 for (Interface intf : interfaces.values()) {
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -07001163 linkDiscoveryService.addToSuppressLLDPs(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -07001164 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001165
Ray Milkey269ffb92014-04-03 14:43:30 -07001166 bgpUpdatesExecutor.execute(new Runnable() {
1167 @Override
1168 public void run() {
1169 doUpdatesThread();
1170 }
1171 });
1172 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001173
Jonathan Hart938a0152014-04-07 18:27:31 -07001174 // Before inserting the paths for BGP traffic, we should check whether
1175 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001176 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001177 // TODO: Fix the code below after topoSwitchSerice was removed
1178 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001179 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001180
Ray Milkey269ffb92014-04-03 14:43:30 -07001181 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1182 getActiveSwitches().iterator();
1183 while(activeSwitches.hasNext())
1184 {
1185 ISwitchObject switchObject = activeSwitches.next();
1186 if (switchObject.getDPID().equals(dpid)) {
1187 break;
1188 }
1189 if(activeSwitches.hasNext() == false) {
1190 log.debug("Not all switches are here yet");
1191 return;
1192 }
1193 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001194 }
1195 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001196 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001197 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001198
Jonathan Hart938a0152014-04-07 18:27:31 -07001199 // Actually we only need to go half way round to verify full mesh connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001200 private void checkTopologyReady() {
1201 for (Interface dstInterface : interfaces.values()) {
1202 for (Interface srcInterface : interfaces.values()) {
1203 if (dstInterface.equals(srcInterface)) {
1204 continue;
1205 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001206
Ray Milkey269ffb92014-04-03 14:43:30 -07001207 // TODO: Fix for the new Topology Network Graph
1208 /*
1209 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1210 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001211
Ray Milkey269ffb92014-04-03 14:43:30 -07001212 if (shortestPath == null){
1213 log.debug("Shortest path between {} and {} not found",
1214 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1215 return;
1216 }
1217 */
1218 }
1219 }
1220 topologyReady = true;
1221 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001222
Ray Milkey269ffb92014-04-03 14:43:30 -07001223 private void checkStatus() {
1224 if (!switchesConnected) {
1225 checkSwitchesConnected();
1226 }
1227 boolean oldTopologyReadyStatus = topologyReady;
1228 if (switchesConnected && !topologyReady) {
1229 checkTopologyReady();
1230 }
1231 if (!oldTopologyReadyStatus && topologyReady) {
1232 beginRouting();
1233 }
1234 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001235
Ray Milkey269ffb92014-04-03 14:43:30 -07001236 private void doUpdatesThread() {
1237 boolean interrupted = false;
1238 try {
1239 while (true) {
1240 try {
1241 RibUpdate update = ribUpdates.take();
1242 switch (update.getOperation()) {
1243 case UPDATE:
1244 if (validateUpdate(update)) {
1245 processRibAdd(update);
1246 } else {
1247 log.debug("Rib UPDATE out of order: {} via {}",
1248 update.getPrefix(), update.getRibEntry().getNextHop());
1249 }
1250 break;
1251 case DELETE:
1252 if (validateUpdate(update)) {
1253 processRibDelete(update);
1254 } else {
1255 log.debug("Rib DELETE out of order: {} via {}",
1256 update.getPrefix(), update.getRibEntry().getNextHop());
1257 }
1258 break;
Ray Milkey0b122ed2014-04-14 10:06:03 -07001259 default:
1260 log.error("Unknown operation {}", update.getOperation());
1261 break;
Ray Milkey269ffb92014-04-03 14:43:30 -07001262 }
1263 } catch (InterruptedException e) {
1264 log.debug("Interrupted while taking from updates queue", e);
1265 interrupted = true;
1266 } catch (Exception e) {
1267 log.debug("exception", e);
1268 }
1269 }
1270 } finally {
1271 if (interrupted) {
1272 Thread.currentThread().interrupt();
1273 }
1274 }
1275 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001276
Ray Milkey269ffb92014-04-03 14:43:30 -07001277 private boolean validateUpdate(RibUpdate update) {
1278 RibEntry newEntry = update.getRibEntry();
1279 RibEntry oldEntry = ptree.lookup(update.getPrefix());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001280
Ray Milkey269ffb92014-04-03 14:43:30 -07001281 //If there is no existing entry we must assume this is the most recent
1282 //update. However this might not always be the case as we might have a
1283 //POST then DELETE reordering.
1284 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1285 if (oldEntry == null) {
1286 return true;
1287 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001288
Ray Milkey269ffb92014-04-03 14:43:30 -07001289 // This handles the case where routes are gathered in the initial
1290 // request because they don't have sequence number info
1291 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1292 return true;
1293 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001294
Ray Milkey269ffb92014-04-03 14:43:30 -07001295 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1296 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001297 }
Ray Milkey4985f212014-04-10 16:57:05 -07001298
1299 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
1300 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -07001301 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001302
Ray Milkey269ffb92014-04-03 14:43:30 -07001303 // The code below should be reimplemented after removal of Floodlight's
1304 // ITopologyService API. It should be implemented on top of network graph
1305 // notifications. (It was pretty hacky anyway...)
1306 /*
1307 @Override
1308 public void topologyChanged() {
1309 if (topologyReady) {
1310 return;
1311 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001312
Ray Milkey269ffb92014-04-03 14:43:30 -07001313 boolean refreshNeeded = false;
1314 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1315 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1316 //We don't need to recalculate anything for just link updates
1317 //They happen very frequently
1318 refreshNeeded = true;
1319 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001320
Ray Milkey269ffb92014-04-03 14:43:30 -07001321 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001322
Ray Milkey269ffb92014-04-03 14:43:30 -07001323 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1324 synchronized (linkUpdates) {
1325 linkUpdates.add(ldu);
1326 }
1327 }
1328 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001329
Ray Milkey269ffb92014-04-03 14:43:30 -07001330 if (refreshNeeded && !topologyReady){
1331 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1332 }
1333 }
1334 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001335
Ray Milkey269ffb92014-04-03 14:43:30 -07001336 @Override
1337 public void addedSwitch(IOFSwitch sw) {
1338 if (!topologyReady) {
1339 sw.clearAllFlowMods();
1340 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001341
Ray Milkey269ffb92014-04-03 14:43:30 -07001342 flowCache.switchConnected(sw);
1343 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001344
Ray Milkey269ffb92014-04-03 14:43:30 -07001345 @Override
1346 public void removedSwitch(IOFSwitch sw) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001347 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001348 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001349
Ray Milkey269ffb92014-04-03 14:43:30 -07001350 @Override
1351 public void switchPortChanged(Long switchId) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001352 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001353 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001354
Ray Milkey269ffb92014-04-03 14:43:30 -07001355 @Override
1356 public String getName() {
1357 return "BgpRoute";
1358 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001359
Ray Milkey269ffb92014-04-03 14:43:30 -07001360 /*
1361 * IConfigInfoService methods
1362 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001363
Ray Milkey269ffb92014-04-03 14:43:30 -07001364 @Override
1365 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hart5e54f2e2014-04-17 13:43:40 -07001366 Interface intf = interfacePtree.match(new Prefix(address.getAddress(), 32));
Ray Milkey269ffb92014-04-03 14:43:30 -07001367 return (intf != null && intf.getIpAddress().equals(address));
1368 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001369
Ray Milkey269ffb92014-04-03 14:43:30 -07001370 @Override
1371 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hart5e54f2e2014-04-17 13:43:40 -07001372 Interface intf = interfacePtree.match(new Prefix(address.getAddress(), 32));
Ray Milkey269ffb92014-04-03 14:43:30 -07001373 return (intf != null && !intf.getIpAddress().equals(address));
1374 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001375
Ray Milkey269ffb92014-04-03 14:43:30 -07001376 @Override
1377 public boolean fromExternalNetwork(long inDpid, short inPort) {
1378 for (Interface intf : interfaces.values()) {
1379 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1380 return true;
1381 }
1382 }
1383 return false;
1384 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001385
Ray Milkey269ffb92014-04-03 14:43:30 -07001386 @Override
1387 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hart5e54f2e2014-04-17 13:43:40 -07001388 return interfacePtree.match(new Prefix(dstIpAddress.getAddress(), 32));
Ray Milkey269ffb92014-04-03 14:43:30 -07001389 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001390
Ray Milkey269ffb92014-04-03 14:43:30 -07001391 @Override
1392 public boolean hasLayer3Configuration() {
1393 return !interfaces.isEmpty();
1394 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001395
Ray Milkey269ffb92014-04-03 14:43:30 -07001396 @Override
1397 public MACAddress getRouterMacAddress() {
1398 return bgpdMacAddress;
1399 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001400
Ray Milkey269ffb92014-04-03 14:43:30 -07001401 @Override
1402 public short getVlan() {
1403 return vlan;
1404 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001405}