blob: d37f8bd87f11cd20c20e901456be04ed1d9fdf98 [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 Hartd1f23252013-06-13 15:17:05 +120055import org.codehaus.jackson.JsonParseException;
56import org.codehaus.jackson.map.JsonMappingException;
57import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070058import org.openflow.protocol.OFFlowMod;
59import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070060import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120061import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070062import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070063import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120064import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080065import org.slf4j.Logger;
66import org.slf4j.LoggerFactory;
67
Jonathan Hart4dfc3652013-08-02 20:22:36 +120068import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120069import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120070import com.google.common.collect.Multimaps;
71import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120072import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120073import com.google.common.util.concurrent.ThreadFactoryBuilder;
74
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070075public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Ray Milkey269ffb92014-04-03 14:43:30 -070076 IArpRequester,
77 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070078
Ray Milkeyec838942014-04-09 11:28:43 -070079 private static final Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080080
Ray Milkey269ffb92014-04-03 14:43:30 -070081 private IFloodlightProviderService floodlightProvider;
82 private ILinkDiscoveryService linkDiscoveryService;
83 private IRestApiService restApi;
84 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070085
Ray Milkey269ffb92014-04-03 14:43:30 -070086 private IPatriciaTrie<RibEntry> ptree;
87 private IPatriciaTrie<Interface> interfacePtrie;
88 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070089
Ray Milkey269ffb92014-04-03 14:43:30 -070090 private String bgpdRestIp;
91 private String routerId;
92 private String configFilename = "config.json";
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070093
Ray Milkey2476cac2014-04-08 11:03:21 -070094 private static final short ARP_PRIORITY = 20;
Ray Milkey5d406012014-04-08 14:44:41 -070095
Jonathan Hart938a0152014-04-07 18:27:31 -070096 // The fields below are unused after the move to FlowManager.
97 // Remove them if no longer needed.
98 /*
99 // We need to identify our flows somehow, in lieu of an OS-wide mechanism
100 // to hand out cookie IDs to prevent conflicts.
101 private static final long APP_COOKIE = 0xa0000000000000L;
102 // Cookie for flows that do L2 forwarding within SDN domain to egress routers
103 private static final long L2_FWD_COOKIE = APP_COOKIE + 1;
104 // Cookie for flows in ingress switches that rewrite the MAC address
105 private static final long MAC_RW_COOKIE = APP_COOKIE + 2;
106 // Cookie for flows that setup BGP paths
107 private static final long BGP_COOKIE = APP_COOKIE + 3;
108 // Forwarding uses priority 0, and the mac rewrite entries in ingress switches
109 // need to be higher priority than this otherwise the rewrite may not get done
110 private static final short SDNIP_PRIORITY = 10;
111 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700112
Ray Milkey2476cac2014-04-08 11:03:21 -0700113 private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700114
Jonathan Hart938a0152014-04-07 18:27:31 -0700115 private static final int TOPO_DETECTION_WAIT = 2; // seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700116
Jonathan Hart938a0152014-04-07 18:27:31 -0700117 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700118 private List<String> switches;
119 private Map<String, Interface> interfaces;
120 private Map<InetAddress, BgpPeer> bgpPeers;
121 private SwitchPort bgpdAttachmentPoint;
122 private MACAddress bgpdMacAddress;
123 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700124
Jonathan Hart938a0152014-04-07 18:27:31 -0700125 // True when all switches have connected
Ray Milkey269ffb92014-04-03 14:43:30 -0700126 private volatile boolean switchesConnected = false;
Jonathan Hart938a0152014-04-07 18:27:31 -0700127 // True when we have a full mesh of shortest paths between gateways
Ray Milkey269ffb92014-04-03 14:43:30 -0700128 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200129
Jonathan Hart938a0152014-04-07 18:27:31 -0700130 private List<LDUpdate> linkUpdates;
Ray Milkey269ffb92014-04-03 14:43:30 -0700131 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700132
Ray Milkey269ffb92014-04-03 14:43:30 -0700133 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700134
Ray Milkey269ffb92014-04-03 14:43:30 -0700135 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700136
Ray Milkey269ffb92014-04-03 14:43:30 -0700137 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700138
Ray Milkey269ffb92014-04-03 14:43:30 -0700139 private Map<InetAddress, Path> pushedPaths;
140 private Map<Prefix, Path> prefixToPath;
141 // private Multimap<Prefix, PushedFlowMod> pushedFlows;
142 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700143
Ray Milkey269ffb92014-04-03 14:43:30 -0700144 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700145
Ray Milkey269ffb92014-04-03 14:43:30 -0700146 // TODO: Fix for the new Topology Network Graph
147 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700148
Ray Milkey269ffb92014-04-03 14:43:30 -0700149 private class TopologyChangeDetector implements Runnable {
150 @Override
151 public void run() {
152 log.debug("Running topology change detection task");
153 synchronized (linkUpdates) {
154 //This is the model the REST API uses to retrieve network graph info
155 // TODO: Fix the code below after topoLinkService was removed
156 /*
157 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700158
Ray Milkey269ffb92014-04-03 14:43:30 -0700159 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700160
Ray Milkey269ffb92014-04-03 14:43:30 -0700161 Iterator<LDUpdate> it = linkUpdates.iterator();
162 while (it.hasNext()){
163 LDUpdate ldu = it.next();
164 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
165 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700166
Ray Milkey269ffb92014-04-03 14:43:30 -0700167 if (activeLinks.contains(l)){
168 it.remove();
169 }
170 }
171 */
172 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700173
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 if (!topologyReady) {
175 if (linkUpdates.isEmpty()) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700176 // All updates have been seen in network map.
177 // We can check if topology is ready
Ray Milkey269ffb92014-04-03 14:43:30 -0700178 log.debug("No known changes outstanding. Checking topology now");
179 checkStatus();
180 } else {
Jonathan Hart938a0152014-04-07 18:27:31 -0700181 // We know of some link updates that haven't propagated to the database yet
Ray Milkey269ffb92014-04-03 14:43:30 -0700182 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
183 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
184 }
185 }
186 }
187 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700188
Ray Milkey269ffb92014-04-03 14:43:30 -0700189 private void readConfiguration(String configFilename) {
190 File gatewaysFile = new File(configFilename);
191 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700192
Ray Milkey269ffb92014-04-03 14:43:30 -0700193 try {
194 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700195
Ray Milkey269ffb92014-04-03 14:43:30 -0700196 switches = config.getSwitches();
197 interfaces = new HashMap<String, Interface>();
198 for (Interface intf : config.getInterfaces()) {
199 interfaces.put(intf.getName(), intf);
200 }
201 bgpPeers = new HashMap<InetAddress, BgpPeer>();
202 for (BgpPeer peer : config.getPeers()) {
203 bgpPeers.put(peer.getIpAddress(), peer);
204 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700205
Ray Milkey269ffb92014-04-03 14:43:30 -0700206 bgpdAttachmentPoint = new SwitchPort(
207 new Dpid(config.getBgpdAttachmentDpid()),
208 new Port(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700209
Ray Milkey269ffb92014-04-03 14:43:30 -0700210 bgpdMacAddress = config.getBgpdMacAddress();
211 vlan = config.getVlan();
212 } catch (JsonParseException e) {
213 log.error("Error in JSON file", e);
214 System.exit(1);
215 } catch (JsonMappingException e) {
216 log.error("Error in JSON file", e);
217 System.exit(1);
218 } catch (IOException e) {
219 log.error("Error reading JSON file", e);
220 System.exit(1);
221 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700222
Jonathan Hart938a0152014-04-07 18:27:31 -0700223 // Populate the interface Patricia Trie
Ray Milkey269ffb92014-04-03 14:43:30 -0700224 for (Interface intf : interfaces.values()) {
225 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
226 interfacePtrie.put(prefix, intf);
227 }
228 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700229
Ray Milkey269ffb92014-04-03 14:43:30 -0700230 @Override
231 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
232 Collection<Class<? extends IFloodlightService>> l
233 = new ArrayList<Class<? extends IFloodlightService>>();
234 l.add(IBgpRouteService.class);
235 l.add(IConfigInfoService.class);
236 return l;
237 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700238
Ray Milkey269ffb92014-04-03 14:43:30 -0700239 @Override
240 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
241 Map<Class<? extends IFloodlightService>, IFloodlightService> m
242 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
243 m.put(IBgpRouteService.class, this);
244 m.put(IConfigInfoService.class, this);
245 return m;
246 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800247
Ray Milkey269ffb92014-04-03 14:43:30 -0700248 @Override
249 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
250 Collection<Class<? extends IFloodlightService>> l
251 = new ArrayList<Class<? extends IFloodlightService>>();
252 l.add(IFloodlightProviderService.class);
253 l.add(IRestApiService.class);
254 return l;
255 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700256
Ray Milkey269ffb92014-04-03 14:43:30 -0700257 @Override
258 public void init(FloodlightModuleContext context)
259 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700260
Ray Milkey269ffb92014-04-03 14:43:30 -0700261 ptree = new PatriciaTrie<RibEntry>(32);
262 interfacePtrie = new PatriciaTrie<Interface>(32);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700263
Ray Milkey269ffb92014-04-03 14:43:30 -0700264 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700265
Ray Milkey269ffb92014-04-03 14:43:30 -0700266 // Register floodlight provider and REST handler.
267 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
268 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
269 restApi = context.getServiceImpl(IRestApiService.class);
270 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800271
Ray Milkey269ffb92014-04-03 14:43:30 -0700272 linkUpdates = new ArrayList<LDUpdate>();
273 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
274 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700275
Ray Milkey269ffb92014-04-03 14:43:30 -0700276 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
277 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
278 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700279
Ray Milkey269ffb92014-04-03 14:43:30 -0700280 pushedPaths = new HashMap<InetAddress, Path>();
281 prefixToPath = new HashMap<Prefix, Path>();
282// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
283 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700284
Ray Milkey269ffb92014-04-03 14:43:30 -0700285 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700286
Ray Milkey269ffb92014-04-03 14:43:30 -0700287 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
288 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700289
Jonathan Hart938a0152014-04-07 18:27:31 -0700290 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700291 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
292 if (bgpdRestIp == null) {
293 log.error("BgpdRestIp property not found in config file");
294 System.exit(1);
295 } else {
296 log.info("BgpdRestIp set to {}", bgpdRestIp);
297 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700298
Ray Milkey269ffb92014-04-03 14:43:30 -0700299 routerId = context.getConfigParams(this).get("RouterId");
300 if (routerId == null) {
301 log.error("RouterId property not found in config file");
302 System.exit(1);
303 } else {
304 log.info("RouterId set to {}", routerId);
305 }
pingping-linba5c52f2014-02-11 16:52:01 -0800306
Ray Milkey269ffb92014-04-03 14:43:30 -0700307 String configFilenameParameter = context.getConfigParams(this).get("configfile");
308 if (configFilenameParameter != null) {
309 configFilename = configFilenameParameter;
310 }
311 log.debug("Config file set to {}", configFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700312
Ray Milkey269ffb92014-04-03 14:43:30 -0700313 readConfiguration(configFilename);
314 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700315
Ray Milkey269ffb92014-04-03 14:43:30 -0700316 @Override
317 public void startUp(FloodlightModuleContext context) {
318 restApi.addRestletRoutable(new BgpRouteWebRoutable());
319 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800320
Jonathan Hart938a0152014-04-07 18:27:31 -0700321 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700322 retrieveRib();
323 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800324
Ray Milkey269ffb92014-04-03 14:43:30 -0700325 @Override
326 public IPatriciaTrie<RibEntry> getPtree() {
327 return ptree;
328 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700329
Ray Milkey269ffb92014-04-03 14:43:30 -0700330 @Override
331 public void clearPtree() {
332 ptree = new PatriciaTrie<RibEntry>(32);
333 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700334
Ray Milkey269ffb92014-04-03 14:43:30 -0700335 @Override
336 public String getBGPdRestIp() {
337 return bgpdRestIp;
338 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700339
Ray Milkey269ffb92014-04-03 14:43:30 -0700340 @Override
341 public String getRouterId() {
342 return routerId;
343 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700344
Ray Milkey269ffb92014-04-03 14:43:30 -0700345 private void retrieveRib() {
346 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
347 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700348
Jonathan Hart938a0152014-04-07 18:27:31 -0700349 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700350 return;
351 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700352
Ray Milkey269ffb92014-04-03 14:43:30 -0700353 response = response.replaceAll("\"", "'");
354 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
Jonathan Hart938a0152014-04-07 18:27:31 -0700355 JSONArray ribArray = jsonObj.getJSONArray("rib");
Ray Milkey2476cac2014-04-08 11:03:21 -0700356 String routerId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700357
Jonathan Hart938a0152014-04-07 18:27:31 -0700358 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700359
Ray Milkey269ffb92014-04-03 14:43:30 -0700360 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700361
Ray Milkey269ffb92014-04-03 14:43:30 -0700362 for (int j = 0; j < size; j++) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700363 JSONObject ribEntry = ribArray.getJSONObject(j);
364 String prefix = ribEntry.getString("prefix");
365 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700366
Jonathan Hart938a0152014-04-07 18:27:31 -0700367 // Insert each rib entry into the local rib
Ray Milkey269ffb92014-04-03 14:43:30 -0700368 String[] substring = prefix.split("/");
369 String prefix1 = substring[0];
370 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700371
Ray Milkey269ffb92014-04-03 14:43:30 -0700372 Prefix p;
373 try {
374 p = new Prefix(prefix1, Integer.valueOf(mask1));
375 } catch (NumberFormatException e) {
376 log.warn("Wrong mask format in RIB JSON: {}", mask1);
377 continue;
378 } catch (IllegalArgumentException e1) {
379 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
380 continue;
381 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700382
Ray Milkey2476cac2014-04-08 11:03:21 -0700383 RibEntry rib = new RibEntry(routerId, nexthop);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700384
Ray Milkey269ffb92014-04-03 14:43:30 -0700385 try {
386 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
387 } catch (InterruptedException e) {
388 log.debug("Interrupted while pushing onto update queue");
389 }
390 }
391 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700392
Ray Milkey269ffb92014-04-03 14:43:30 -0700393 @Override
394 public void newRibUpdate(RibUpdate update) {
395 try {
396 ribUpdates.put(update);
397 } catch (InterruptedException e) {
398 log.debug("Interrupted while putting on ribUpdates queue", e);
399 Thread.currentThread().interrupt();
400 }
401 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700402
Jonathan Hart938a0152014-04-07 18:27:31 -0700403 public void processRibAdd(RibUpdate update) {
404 synchronized (this) {
405 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700406
Jonathan Hart938a0152014-04-07 18:27:31 -0700407 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700408
Jonathan Hart938a0152014-04-07 18:27:31 -0700409 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700410
Jonathan Hart938a0152014-04-07 18:27:31 -0700411 if (rib != null && !rib.equals(update.getRibEntry())) {
412 // There was an existing nexthop for this prefix. This update supersedes that,
413 // so we need to remove the old flows for this prefix from the switches
414 _processDeletePrefix(prefix, rib);
415 }
Ray Milkey5d406012014-04-08 14:44:41 -0700416
Jonathan Hart938a0152014-04-07 18:27:31 -0700417 if (update.getRibEntry().getNextHop().equals(
418 InetAddresses.forString("0.0.0.0"))) {
419 // Route originated by SDN domain
420 // We don't handle these at the moment
421 log.debug("Own route {} to {}", prefix,
422 update.getRibEntry().getNextHop().getHostAddress());
423 return;
424 }
Ray Milkey5d406012014-04-08 14:44:41 -0700425
Jonathan Hart938a0152014-04-07 18:27:31 -0700426 _processRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700427 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700428 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700429
Ray Milkey269ffb92014-04-03 14:43:30 -0700430 private void _processRibAdd(RibUpdate update) {
431 Prefix prefix = update.getPrefix();
432 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700433
Ray Milkey269ffb92014-04-03 14:43:30 -0700434 InetAddress dstIpAddress = rib.getNextHop();
435 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800436
Ray Milkey269ffb92014-04-03 14:43:30 -0700437 // See if we know the MAC address of the next hop
438 // TODO if we do not treat the next hop as a device in the future, we need to update this
439 // TODO: Fix the code below after deviceStorage was removed
440 /*
441 IDeviceObject nextHopDevice =
442 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700443
Ray Milkey269ffb92014-04-03 14:43:30 -0700444 if (nextHopDevice == null){
445 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
446 prefixesWaitingOnArp.put(dstIpAddress,
447 new RibUpdate(Operation.UPDATE, prefix, rib));
448 proxyArp.sendArpRequest(dstIpAddress, this, true);
449 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800450
Ray Milkey269ffb92014-04-03 14:43:30 -0700451 }
452 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
453 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700454
Ray Milkey269ffb92014-04-03 14:43:30 -0700455 // Find the attachment point (egress interface) of the next hop
456 Interface egressInterface = null;
457 if (bgpPeers.containsKey(dstIpAddress)) {
458 //Route to a peer
459 log.debug("Route to peer {}", dstIpAddress);
460 BgpPeer peer = bgpPeers.get(dstIpAddress);
461 egressInterface = interfaces.get(peer.getInterfaceName());
462 } else {
463 //Route to non-peer
464 log.debug("Route to non-peer {}", dstIpAddress);
465 egressInterface = interfacePtrie.match(
466 new Prefix(dstIpAddress.getAddress(), 32));
467 if (egressInterface == null) {
468 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
469 return;
470 }
471 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700472
Ray Milkey269ffb92014-04-03 14:43:30 -0700473 if (nextHopMacAddress == null) {
474 prefixesWaitingOnArp.put(dstIpAddress,
475 new RibUpdate(Operation.UPDATE, prefix, rib));
476 proxyArp.sendArpRequest(dstIpAddress, this, true);
477 return;
478 } else {
479 if (!bgpPeers.containsKey(dstIpAddress)) {
480 //If the prefix is for a non-peer we need to ensure there's a path,
481 //and push one if there isn't.
482 Path path = pushedPaths.get(dstIpAddress);
483 if (path == null) {
484 path = new Path(egressInterface, dstIpAddress);
485 calculateAndPushPath(path, nextHopMacAddress);
486 pushedPaths.put(dstIpAddress, path);
487 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700488
Ray Milkey269ffb92014-04-03 14:43:30 -0700489 path.incrementUsers();
490 prefixToPath.put(prefix, path);
491 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700492
Ray Milkey269ffb92014-04-03 14:43:30 -0700493 //For all prefixes we need to add the first-hop mac-rewriting flows
494 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
495 }
496 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700497
Ray Milkey269ffb92014-04-03 14:43:30 -0700498 /**
499 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
500 * to all other border switches
501 */
502 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
503 MACAddress nextHopMacAddress) {
504 log.debug("Adding flows for prefix {}, next hop mac {}",
505 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700506
Ray Milkey269ffb92014-04-03 14:43:30 -0700507 FlowPath flowPath = new FlowPath();
508 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700509
Ray Milkey269ffb92014-04-03 14:43:30 -0700510 // Set flowPath FlowPathType and FlowPathUserState
511 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
512 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800513
Ray Milkey269ffb92014-04-03 14:43:30 -0700514 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
515 // only to the first-host switches
516 FlowPathFlags flowPathFlags = new FlowPathFlags();
517 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
518 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800519
Ray Milkey269ffb92014-04-03 14:43:30 -0700520 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700521 SwitchPort dstPort =
522 new SwitchPort(new Dpid(egressInterface.getDpid()),
523 new Port(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800524
Ray Milkey269ffb92014-04-03 14:43:30 -0700525 // We only need one flow mod per switch, so pick one interface on each switch
526 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
527 for (Interface intf : interfaces.values()) {
528 if (!srcInterfaces.containsKey(intf.getDpid())
529 && !intf.equals(egressInterface)) {
530 srcInterfaces.put(intf.getDpid(), intf);
531 }
532 }
533 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800534
Ray Milkey269ffb92014-04-03 14:43:30 -0700535 if (egressInterface.equals(srcInterface)) {
536 continue;
537 }
pingping-linba5c52f2014-02-11 16:52:01 -0800538
Ray Milkey269ffb92014-04-03 14:43:30 -0700539 // Create flowPath FlowId
540 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800541
Ray Milkey269ffb92014-04-03 14:43:30 -0700542 // Create DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700543 SwitchPort srcPort =
544 new SwitchPort(new Dpid(srcInterface.getDpid()),
545 new Port(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800546
Ray Milkey269ffb92014-04-03 14:43:30 -0700547 DataPath dataPath = new DataPath();
548 dataPath.setSrcPort(srcPort);
549 dataPath.setDstPort(dstPort);
550 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800551
Ray Milkey269ffb92014-04-03 14:43:30 -0700552 // Create flow path matching condition(s): IPv4 Prefix
553 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700554 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700555 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
556 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
557 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300558
Ray Milkey269ffb92014-04-03 14:43:30 -0700559 /*
560 * Create the Flow Entry Action(s): dst-MAC rewrite action
561 */
562 FlowEntryActions flowEntryActions = new FlowEntryActions();
563 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
564 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
565 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
566 flowEntryActions.addAction(flowEntryAction1);
567 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800568
Ray Milkey269ffb92014-04-03 14:43:30 -0700569 // Flow Path installation, only to first hop switches
570 // TODO: Add the flow by using the new Path Intent framework
571 /*
572 if (flowManagerService.addFlow(flowPath) == null) {
573 log.error("Failed to install flow path to the first hop for " +
574 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
575 nextHopMacAddress);
576 }
577 else {
578 log.debug("Successfully installed flow path to the first hop " +
579 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
580 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800581
Ray Milkey269ffb92014-04-03 14:43:30 -0700582 pushedFlowIds.put(prefix, flowPath.flowId());
583 }
584 */
585 }
586 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700587
Jonathan Hart938a0152014-04-07 18:27:31 -0700588 public void processRibDelete(RibUpdate update) {
589 synchronized (this) {
590 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700591
Jonathan Hart938a0152014-04-07 18:27:31 -0700592 if (ptree.remove(prefix, update.getRibEntry())) {
593 /*
594 * Only delete flows if an entry was actually removed from the trie.
595 * If no entry was removed, the <prefix, nexthop> wasn't there so
596 * it's probably already been removed and we don't need to do anything
597 */
598 _processDeletePrefix(prefix, update.getRibEntry());
599 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700600 }
601 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700602
Ray Milkey269ffb92014-04-03 14:43:30 -0700603 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
604 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700605
Ray Milkey269ffb92014-04-03 14:43:30 -0700606 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700607
Ray Milkey269ffb92014-04-03 14:43:30 -0700608 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
609 log.debug("Getting path for route with non-peer nexthop");
610 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700611
Ray Milkey269ffb92014-04-03 14:43:30 -0700612 if (path != null) {
613 //path could be null if we added to the Ptree but didn't push
614 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700615
Ray Milkey269ffb92014-04-03 14:43:30 -0700616 path.decrementUsers();
617 if (path.getUsers() <= 0 && !path.isPermanent()) {
618 deletePath(path);
619 pushedPaths.remove(path.getDstIpAddress());
620 }
621 }
622 }
623 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700624
Ray Milkey269ffb92014-04-03 14:43:30 -0700625 // TODO have not tested this module
626 private void deletePrefixFlows(Prefix prefix) {
627 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700628
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700629 //
630 // TODO: Delete the flow by using the new Path Intent framework
631 // NOTE: During the refactoring of the code below, if obtaining
632 // the values of the removed flowIds is needed, the first
633 // removeAll() statement should be replaced with the second removeAll()
634 // statement.
635 //
636 pushedFlowIds.removeAll(prefix);
637 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700638 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
639 for (FlowId flowId : flowIds) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700640 if (log.isTraceEnabled()) {
641 //Trace the flow status by flowPath in the switch before deleting it
642 log.trace("Pushing a DELETE flow mod to flowPath : {}",
643 flowManagerService.getFlow(flowId).toString());
644 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700645
Ray Milkey269ffb92014-04-03 14:43:30 -0700646 if( flowManagerService.deleteFlow(flowId))
647 {
648 log.debug("Successfully deleted FlowId: {}",flowId);
649 }
650 else
651 {
652 log.debug("Failed to delete FlowId: {}",flowId);
653 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700654 }
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700655 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700656 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700657
Ray Milkey269ffb92014-04-03 14:43:30 -0700658 // TODO need to record the path and then delete here
659 private void deletePath(Path path) {
660 log.debug("Deleting flows for path to {}",
661 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700662
Ray Milkey269ffb92014-04-03 14:43:30 -0700663 // TODO need update
664 /*for (PushedFlowMod pfm : path.getFlowMods()) {
665 if (log.isTraceEnabled()) {
666 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
667 new Object[] {HexString.toHexString(pfm.getDpid()),
668 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
669 });
670 }
pingping-linba5c52f2014-02-11 16:52:01 -0800671
Ray Milkey269ffb92014-04-03 14:43:30 -0700672 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
673 }*/
674 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700675
676
Ray Milkey269ffb92014-04-03 14:43:30 -0700677 //TODO test next-hop changes
678 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800679
Ray Milkey269ffb92014-04-03 14:43:30 -0700680 /**
681 * On startup, we need to calculate a full mesh of paths between all gateway
682 * switches
683 */
684 private void setupFullMesh() {
685 //For each border router, calculate and install a path from every other
686 //border switch to said border router. However, don't install the entry
687 //in to the first hop switch, as we need to install an entry to rewrite
688 //for each prefix received. This will be done later when prefixes have
689 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700690
Ray Milkey269ffb92014-04-03 14:43:30 -0700691 for (BgpPeer peer : bgpPeers.values()) {
692 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700693
Ray Milkey269ffb92014-04-03 14:43:30 -0700694 //We know there's not already a Path here pushed, because this is
695 //called before all other routing
696 Path path = new Path(peerInterface, peer.getIpAddress());
697 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700698
Ray Milkey269ffb92014-04-03 14:43:30 -0700699 //See if we know the MAC address of the peer. If not we can't
700 //do anything until we learn it
701 // TODO: Fix the code below after deviceStorage was removed
702 MACAddress macAddress = null;
703 /*
704 IDeviceObject nextHopDevice =
705 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800706
Ray Milkey269ffb92014-04-03 14:43:30 -0700707 if(nextHopDevice == null){
708 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
709 //Put in the pending paths list first
710 pathsWaitingOnArp.put(peer.getIpAddress(), path);
711 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
712 continue;
713 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700714
Ray Milkey269ffb92014-04-03 14:43:30 -0700715 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
716 */
pingping-linba5c52f2014-02-11 16:52:01 -0800717
Ray Milkey269ffb92014-04-03 14:43:30 -0700718 if (macAddress == null) {
719 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
720 //Put in the pending paths list first
721 pathsWaitingOnArp.put(peer.getIpAddress(), path);
722 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
723 continue;
724 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700725
Ray Milkey269ffb92014-04-03 14:43:30 -0700726 //If we know the MAC, lets go ahead and push the paths to this peer
727 calculateAndPushPath(path, macAddress);
728 }
729 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700730
Ray Milkey269ffb92014-04-03 14:43:30 -0700731 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
732 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700733
Ray Milkey269ffb92014-04-03 14:43:30 -0700734 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
735 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800736
Ray Milkey269ffb92014-04-03 14:43:30 -0700737 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800738
Ray Milkey269ffb92014-04-03 14:43:30 -0700739 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800740
Ray Milkey269ffb92014-04-03 14:43:30 -0700741 // Set flowPath FlowPathType and FlowPathUserState
742 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
743 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800744
Ray Milkey269ffb92014-04-03 14:43:30 -0700745 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
746 FlowPathFlags flowPathFlags = new FlowPathFlags();
747 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
748 flowPath.setFlowPathFlags(flowPathFlags);
749
750 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700751 SwitchPort dstPort =
752 new SwitchPort(new Dpid(dstInterface.getDpid()),
753 new Port(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800754
Ray Milkey269ffb92014-04-03 14:43:30 -0700755 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800756
Ray Milkey269ffb92014-04-03 14:43:30 -0700757 if (dstInterface.equals(srcInterface)) {
758 continue;
759 }
pingping-linba5c52f2014-02-11 16:52:01 -0800760
Ray Milkey269ffb92014-04-03 14:43:30 -0700761 // Create flowPath FlowId
762 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800763
Ray Milkey269ffb92014-04-03 14:43:30 -0700764 // Create the DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700765 SwitchPort srcPort =
766 new SwitchPort(new Dpid(srcInterface.getDpid()),
767 new Port(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800768
Ray Milkey269ffb92014-04-03 14:43:30 -0700769 DataPath dataPath = new DataPath();
770 dataPath.setSrcPort(srcPort);
771 dataPath.setDstPort(dstPort);
772 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800773
Ray Milkey269ffb92014-04-03 14:43:30 -0700774 // Create the Flow Path Match condition(s)
775 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700776 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700777 flowEntryMatch.enableDstMac(dstMacAddress);
778 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800779
Ray Milkey269ffb92014-04-03 14:43:30 -0700780 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
781 // Shortest Path Flow, and is always the last action for the Flow Entries
782 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
783 // TODO: Add the flow by using the new Path Intent framework
784 /*
785 if (flowManagerService.addFlow(flowPath) == null) {
786 log.error("Failed to set up MAC based forwarding path to {}, {}",
787 path.getDstIpAddress().getHostAddress(),dstMacAddress);
788 }
789 else {
790 log.debug("Successfully set up MAC based forwarding path to {}, {}",
791 path.getDstIpAddress().getHostAddress(),dstMacAddress);
792 }
793 */
794 }
795 }
pingping-linba5c52f2014-02-11 16:52:01 -0800796
Ray Milkey269ffb92014-04-03 14:43:30 -0700797 /**
Jonathan Hart938a0152014-04-07 18:27:31 -0700798 * Proactively install all BGP traffic paths from BGP host attachment point
Ray Milkey269ffb92014-04-03 14:43:30 -0700799 * in SDN network to all the virtual gateways to BGP peers in other networks
800 */
801 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200802
Ray Milkey269ffb92014-04-03 14:43:30 -0700803 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800804
Ray Milkey269ffb92014-04-03 14:43:30 -0700805 FlowPath flowPath = new FlowPath();
806 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800807
Ray Milkey269ffb92014-04-03 14:43:30 -0700808 // Set flowPath FlowPathType and FlowPathUserState
809 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
810 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800811
Ray Milkey269ffb92014-04-03 14:43:30 -0700812 // Install flow paths between BGPd and its peers
813 // There is no need to set the FlowPathFlags
814 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800815
Ray Milkey269ffb92014-04-03 14:43:30 -0700816 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
pingping-linba5c52f2014-02-11 16:52:01 -0800817
Ray Milkey269ffb92014-04-03 14:43:30 -0700818 // Create the Flow Path Match condition(s)
819 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700820 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
pingping-linba5c52f2014-02-11 16:52:01 -0800821
Ray Milkey269ffb92014-04-03 14:43:30 -0700822 // Match both source address and dest address
823 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress() + "/32");
824 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800825
Ray Milkey269ffb92014-04-03 14:43:30 -0700826 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress().getHostAddress() + "/32");
827 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800828
Ray Milkey269ffb92014-04-03 14:43:30 -0700829 // Match TCP protocol
830 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800831
Ray Milkey269ffb92014-04-03 14:43:30 -0700832 // Match destination TCP port
833 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
834 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800835
Ray Milkey269ffb92014-04-03 14:43:30 -0700836 /**
837 * Create the DataPath: BGP -> BGP peer
838 */
839 // Flow path for src-TCP-port
840 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800841
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700842 SwitchPort srcPort =
843 new SwitchPort(bgpdAttachmentPoint.dpid(),
844 bgpdAttachmentPoint.port());
Ray Milkey269ffb92014-04-03 14:43:30 -0700845 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800846
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700847 SwitchPort dstPort =
848 new SwitchPort(new Dpid(peerInterface.getDpid()),
849 new Port(peerInterface.getSwitchPort().port()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700850 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800851
Ray Milkey269ffb92014-04-03 14:43:30 -0700852 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800853
Ray Milkey269ffb92014-04-03 14:43:30 -0700854 // TODO: Add the flow by using the new Path Intent framework
855 /*
856 if (flowManagerService.addFlow(flowPath) == null) {
857 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
858 bgpPeer.getIpAddress().getHostAddress());
859 }
860 else {
861 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
862 bgpPeer.getIpAddress().getHostAddress());
863 }
864 */
pingping-linba5c52f2014-02-11 16:52:01 -0800865
Ray Milkey269ffb92014-04-03 14:43:30 -0700866 // Disable dst-TCP-port, and set src-TCP-port
867 flowEntryMatch.disableDstTcpUdpPort();
868 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
869 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800870
Ray Milkey269ffb92014-04-03 14:43:30 -0700871 // Create a new FlowId
872 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800873
Ray Milkey269ffb92014-04-03 14:43:30 -0700874 // TODO: Add the flow by using the new Path Intent framework
875 /*
876 if (flowManagerService.addFlow(flowPath) == null) {
877 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
878 bgpPeer.getIpAddress().getHostAddress());
879 }
880 else {
881 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
882 bgpPeer.getIpAddress().getHostAddress());
883 }
884 */
pingping-linba5c52f2014-02-11 16:52:01 -0800885
Ray Milkey269ffb92014-04-03 14:43:30 -0700886 /**
887 * Create the DataPath: BGP <-BGP peer
888 */
889 // Reversed BGP flow path for src-TCP-port
890 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800891
Ray Milkey2476cac2014-04-08 11:03:21 -0700892 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800893
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700894 SwitchPort reverseDstPort =
895 new SwitchPort(bgpdAttachmentPoint.dpid(),
896 bgpdAttachmentPoint.port());
Ray Milkey2476cac2014-04-08 11:03:21 -0700897 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800898
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700899 SwitchPort reverseSrcPort =
900 new SwitchPort(new Dpid(peerInterface.getDpid()),
901 new Port(peerInterface.getSwitchPort().port()));
Ray Milkey2476cac2014-04-08 11:03:21 -0700902 reverseDataPath.setSrcPort(reverseSrcPort);
903 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800904
Jonathan Hart938a0152014-04-07 18:27:31 -0700905 // Reverse the dst IP and src IP addresses
Ray Milkey269ffb92014-04-03 14:43:30 -0700906 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
907 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
908 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800909
Ray Milkey269ffb92014-04-03 14:43:30 -0700910 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800911
Ray Milkey269ffb92014-04-03 14:43:30 -0700912 // TODO: Add the flow by using the new Path Intent framework
913 /*
914 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800915
Ray Milkey269ffb92014-04-03 14:43:30 -0700916 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
917 bgpPeer.getIpAddress().getHostAddress());
918 }
919 else {
920 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
921 bgpPeer.getIpAddress().getHostAddress());
922 }
923 */
pingping-linba5c52f2014-02-11 16:52:01 -0800924
Ray Milkey269ffb92014-04-03 14:43:30 -0700925 // Reversed BGP flow path for dst-TCP-port
926 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800927
Ray Milkey269ffb92014-04-03 14:43:30 -0700928 // Disable src-TCP-port, and set the dst-TCP-port
929 flowEntryMatch.disableSrcTcpUdpPort();
930 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
931 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800932
Ray Milkey269ffb92014-04-03 14:43:30 -0700933 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800934
Ray Milkey269ffb92014-04-03 14:43:30 -0700935 // TODO: Add the flow by using the new Path Intent framework
936 /*
937 if (flowManagerService.addFlow(flowPath) == null) {
938 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
939 bgpPeer.getIpAddress().getHostAddress());
940 }
941 else {
942 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
943 bgpPeer.getIpAddress().getHostAddress());
944 }
945 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700946
Ray Milkey269ffb92014-04-03 14:43:30 -0700947 /**
948 * ICMP paths between BGPd and its peers
949 */
Jonathan Hart938a0152014-04-07 18:27:31 -0700950 // match ICMP protocol BGP <- Peer
Ray Milkey269ffb92014-04-03 14:43:30 -0700951 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800952
Ray Milkey269ffb92014-04-03 14:43:30 -0700953 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
954 flowEntryMatch.disableSrcTcpUdpPort();
955 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -0800956
Ray Milkey269ffb92014-04-03 14:43:30 -0700957 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800958
Ray Milkey2476cac2014-04-08 11:03:21 -0700959 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800960
Ray Milkey269ffb92014-04-03 14:43:30 -0700961 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800962
Ray Milkey269ffb92014-04-03 14:43:30 -0700963 // TODO: Add the flow by using the new Path Intent framework
964 /*
965 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800966
Ray Milkey269ffb92014-04-03 14:43:30 -0700967 log.error("Failed to set up ICMP path BGP <- Peer {}",
968 bgpPeer.getIpAddress().getHostAddress());
969 }
970 else {
971 log.debug("Successfully set up ICMP path BGP <- Peer {}",
972 bgpPeer.getIpAddress().getHostAddress());
973 }
974 */
pingping-linba5c52f2014-02-11 16:52:01 -0800975
Jonathan Hart938a0152014-04-07 18:27:31 -0700976 // match ICMP protocol BGP -> Peer
Ray Milkey269ffb92014-04-03 14:43:30 -0700977 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800978
Ray Milkey269ffb92014-04-03 14:43:30 -0700979 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
980 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
981 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800982
Ray Milkey269ffb92014-04-03 14:43:30 -0700983 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800984
Ray Milkey269ffb92014-04-03 14:43:30 -0700985 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800986
Ray Milkey269ffb92014-04-03 14:43:30 -0700987 // TODO: Add the flow by using the new Path Intent framework
988 /*
989 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800990
Ray Milkey269ffb92014-04-03 14:43:30 -0700991 log.error("Failed to set up ICMP path BGP -> Peer {}",
992 bgpPeer.getIpAddress().getHostAddress());
993 }
994 else {
995 log.debug("Successfully set up ICMP path BGP -> Peer {}",
996 bgpPeer.getIpAddress().getHostAddress());
997 }
998 */
999 }
1000 }
pingping-linba5c52f2014-02-11 16:52:01 -08001001
Ray Milkey269ffb92014-04-03 14:43:30 -07001002 @Override
1003 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
1004 log.debug("Received ARP response: {} => {}",
1005 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001006
Ray Milkey269ffb92014-04-03 14:43:30 -07001007 /*
1008 * We synchronize on this to prevent changes to the ptree while we're pushing
1009 * flows to the switches. If the ptree changes, the ptree and switches
1010 * could get out of sync.
1011 */
1012 synchronized (this) {
1013 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001014
Ray Milkey269ffb92014-04-03 14:43:30 -07001015 if (path != null) {
1016 log.debug("Pushing path to {} at {} on {}", new Object[]{
1017 path.getDstIpAddress().getHostAddress(), macAddress,
1018 path.getDstInterface().getSwitchPort()});
Jonathan Hart938a0152014-04-07 18:27:31 -07001019 // These paths should always be to BGP peers. Paths to non-peers are
1020 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -07001021 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001022 // A path already got pushed to this endpoint while we were waiting
1023 // for ARP. We'll copy over the permanent attribute if it is set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -07001024 if (path.isPermanent()) {
1025 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1026 }
1027 } else {
1028 calculateAndPushPath(path, macAddress);
1029 pushedPaths.put(path.getDstIpAddress(), path);
1030 }
1031 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001032
Ray Milkey269ffb92014-04-03 14:43:30 -07001033 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001034
Ray Milkey269ffb92014-04-03 14:43:30 -07001035 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001036 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001037
Ray Milkey269ffb92014-04-03 14:43:30 -07001038 RibEntry rib = ptree.lookup(update.getPrefix());
1039 if (rib != null && rib.equals(update.getRibEntry())) {
1040 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1041 rib.getNextHop().getHostAddress());
Jonathan Hart938a0152014-04-07 18:27:31 -07001042 // We only push prefix flows if the prefix is still in the ptree
1043 // and the next hop is the same as our update. The prefix could
1044 // have been removed while we were waiting for the ARP, or the
1045 // next hop could have changed.
Ray Milkey269ffb92014-04-03 14:43:30 -07001046 _processRibAdd(update);
1047 } else {
1048 log.debug("Received ARP response, but {},{} is no longer in ptree",
1049 update.getPrefix(), update.getRibEntry());
1050 }
1051 }
1052 }
1053 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001054
Jonathan Hart938a0152014-04-07 18:27:31 -07001055 // TODO wait the priority module of the flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001056 private void setupArpFlows() {
1057 OFMatch match = new OFMatch();
1058 match.setDataLayerType(Ethernet.TYPE_ARP);
1059 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001060
Ray Milkey269ffb92014-04-03 14:43:30 -07001061 OFFlowMod fm = new OFFlowMod();
1062 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001063
Ray Milkey269ffb92014-04-03 14:43:30 -07001064 OFActionOutput action = new OFActionOutput();
1065 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1066 action.setMaxLength((short) 0xffff);
1067 List<OFAction> actions = new ArrayList<OFAction>(1);
1068 actions.add(action);
1069 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001070
Ray Milkey269ffb92014-04-03 14:43:30 -07001071 fm.setIdleTimeout((short) 0)
1072 .setHardTimeout((short) 0)
1073 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1074 .setCookie(0)
1075 .setCommand(OFFlowMod.OFPFC_ADD)
1076 .setPriority(ARP_PRIORITY)
1077 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001078
Ray Milkey269ffb92014-04-03 14:43:30 -07001079 for (String strdpid : switches) {
1080 flowCache.write(HexString.toLong(strdpid), fm);
1081 }
1082 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001083
Jonathan Hart938a0152014-04-07 18:27:31 -07001084 // TODO need update, waiting for the priority feature from flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001085 private void setupDefaultDropFlows() {
1086 OFFlowMod fm = new OFFlowMod();
1087 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -07001088 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001089
Ray Milkey269ffb92014-04-03 14:43:30 -07001090 fm.setIdleTimeout((short) 0)
1091 .setHardTimeout((short) 0)
1092 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1093 .setCookie(0)
1094 .setCommand(OFFlowMod.OFPFC_ADD)
1095 .setPriority((short) 0)
1096 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001097
Ray Milkey269ffb92014-04-03 14:43:30 -07001098 OFFlowMod fmLLDP;
1099 OFFlowMod fmBDDP;
1100 try {
1101 fmLLDP = fm.clone();
1102 fmBDDP = fm.clone();
1103 } catch (CloneNotSupportedException e1) {
1104 log.error("Error cloning flow mod", e1);
1105 return;
1106 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001107
Ray Milkey269ffb92014-04-03 14:43:30 -07001108 OFMatch matchLLDP = new OFMatch();
1109 matchLLDP.setDataLayerType((short) 0x88cc);
1110 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1111 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001112
Ray Milkey269ffb92014-04-03 14:43:30 -07001113 OFMatch matchBDDP = new OFMatch();
1114 matchBDDP.setDataLayerType((short) 0x8942);
1115 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1116 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001117
Ray Milkey269ffb92014-04-03 14:43:30 -07001118 OFActionOutput action = new OFActionOutput();
1119 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1120 action.setMaxLength((short) 0xffff);
1121 List<OFAction> actions = new ArrayList<OFAction>(1);
1122 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001123
Ray Milkey269ffb92014-04-03 14:43:30 -07001124 fmLLDP.setActions(actions);
1125 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001126
Ray Milkey269ffb92014-04-03 14:43:30 -07001127 fmLLDP.setPriority(ARP_PRIORITY);
1128 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1129 fmBDDP.setPriority(ARP_PRIORITY);
1130 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001131
Ray Milkey269ffb92014-04-03 14:43:30 -07001132 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1133 flowModList.add(fm);
1134 flowModList.add(fmLLDP);
1135 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001136
Ray Milkey269ffb92014-04-03 14:43:30 -07001137 for (String strdpid : switches) {
1138 flowCache.write(HexString.toLong(strdpid), flowModList);
1139 }
1140 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001141
Ray Milkey269ffb92014-04-03 14:43:30 -07001142 private void beginRouting() {
1143 log.debug("Topology is now ready, beginning routing function");
1144 // TODO: Fix for the new Topology Network Graph
1145 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001146
Ray Milkey269ffb92014-04-03 14:43:30 -07001147 // Wait Pavlin's API. We need the following functions.
1148 /*setupArpFlows();
1149 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001150
Ray Milkey269ffb92014-04-03 14:43:30 -07001151 setupBgpPaths();
1152 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001153
Ray Milkey269ffb92014-04-03 14:43:30 -07001154 //Suppress link discovery on external-facing router ports
1155 for (Interface intf : interfaces.values()) {
1156 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1157 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001158
Ray Milkey269ffb92014-04-03 14:43:30 -07001159 bgpUpdatesExecutor.execute(new Runnable() {
1160 @Override
1161 public void run() {
1162 doUpdatesThread();
1163 }
1164 });
1165 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001166
Jonathan Hart938a0152014-04-07 18:27:31 -07001167 // Before inserting the paths for BGP traffic, we should check whether
1168 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001169 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001170 // TODO: Fix the code below after topoSwitchSerice was removed
1171 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001172 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001173
Ray Milkey269ffb92014-04-03 14:43:30 -07001174 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1175 getActiveSwitches().iterator();
1176 while(activeSwitches.hasNext())
1177 {
1178 ISwitchObject switchObject = activeSwitches.next();
1179 if (switchObject.getDPID().equals(dpid)) {
1180 break;
1181 }
1182 if(activeSwitches.hasNext() == false) {
1183 log.debug("Not all switches are here yet");
1184 return;
1185 }
1186 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001187 }
1188 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001189 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001190 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001191
Jonathan Hart938a0152014-04-07 18:27:31 -07001192 // Actually we only need to go half way round to verify full mesh connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001193 private void checkTopologyReady() {
1194 for (Interface dstInterface : interfaces.values()) {
1195 for (Interface srcInterface : interfaces.values()) {
1196 if (dstInterface.equals(srcInterface)) {
1197 continue;
1198 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001199
Ray Milkey269ffb92014-04-03 14:43:30 -07001200 // TODO: Fix for the new Topology Network Graph
1201 /*
1202 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1203 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001204
Ray Milkey269ffb92014-04-03 14:43:30 -07001205 if (shortestPath == null){
1206 log.debug("Shortest path between {} and {} not found",
1207 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1208 return;
1209 }
1210 */
1211 }
1212 }
1213 topologyReady = true;
1214 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001215
Ray Milkey269ffb92014-04-03 14:43:30 -07001216 private void checkStatus() {
1217 if (!switchesConnected) {
1218 checkSwitchesConnected();
1219 }
1220 boolean oldTopologyReadyStatus = topologyReady;
1221 if (switchesConnected && !topologyReady) {
1222 checkTopologyReady();
1223 }
1224 if (!oldTopologyReadyStatus && topologyReady) {
1225 beginRouting();
1226 }
1227 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001228
Ray Milkey269ffb92014-04-03 14:43:30 -07001229 private void doUpdatesThread() {
1230 boolean interrupted = false;
1231 try {
1232 while (true) {
1233 try {
1234 RibUpdate update = ribUpdates.take();
1235 switch (update.getOperation()) {
1236 case UPDATE:
1237 if (validateUpdate(update)) {
1238 processRibAdd(update);
1239 } else {
1240 log.debug("Rib UPDATE out of order: {} via {}",
1241 update.getPrefix(), update.getRibEntry().getNextHop());
1242 }
1243 break;
1244 case DELETE:
1245 if (validateUpdate(update)) {
1246 processRibDelete(update);
1247 } else {
1248 log.debug("Rib DELETE out of order: {} via {}",
1249 update.getPrefix(), update.getRibEntry().getNextHop());
1250 }
1251 break;
1252 }
1253 } catch (InterruptedException e) {
1254 log.debug("Interrupted while taking from updates queue", e);
1255 interrupted = true;
1256 } catch (Exception e) {
1257 log.debug("exception", e);
1258 }
1259 }
1260 } finally {
1261 if (interrupted) {
1262 Thread.currentThread().interrupt();
1263 }
1264 }
1265 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001266
Ray Milkey269ffb92014-04-03 14:43:30 -07001267 private boolean validateUpdate(RibUpdate update) {
1268 RibEntry newEntry = update.getRibEntry();
1269 RibEntry oldEntry = ptree.lookup(update.getPrefix());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001270
Ray Milkey269ffb92014-04-03 14:43:30 -07001271 //If there is no existing entry we must assume this is the most recent
1272 //update. However this might not always be the case as we might have a
1273 //POST then DELETE reordering.
1274 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1275 if (oldEntry == null) {
1276 return true;
1277 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001278
Ray Milkey269ffb92014-04-03 14:43:30 -07001279 // This handles the case where routes are gathered in the initial
1280 // request because they don't have sequence number info
1281 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1282 return true;
1283 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001284
Ray Milkey269ffb92014-04-03 14:43:30 -07001285 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1286 return true;
1287 } else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1288 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1289 return true;
1290 } else {
1291 return false;
1292 }
1293 } else {
1294 return false;
1295 }
1296 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001297
Ray Milkey269ffb92014-04-03 14:43:30 -07001298 // The code below should be reimplemented after removal of Floodlight's
1299 // ITopologyService API. It should be implemented on top of network graph
1300 // notifications. (It was pretty hacky anyway...)
1301 /*
1302 @Override
1303 public void topologyChanged() {
1304 if (topologyReady) {
1305 return;
1306 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001307
Ray Milkey269ffb92014-04-03 14:43:30 -07001308 boolean refreshNeeded = false;
1309 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1310 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1311 //We don't need to recalculate anything for just link updates
1312 //They happen very frequently
1313 refreshNeeded = true;
1314 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001315
Ray Milkey269ffb92014-04-03 14:43:30 -07001316 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001317
Ray Milkey269ffb92014-04-03 14:43:30 -07001318 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1319 synchronized (linkUpdates) {
1320 linkUpdates.add(ldu);
1321 }
1322 }
1323 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001324
Ray Milkey269ffb92014-04-03 14:43:30 -07001325 if (refreshNeeded && !topologyReady){
1326 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1327 }
1328 }
1329 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001330
Ray Milkey269ffb92014-04-03 14:43:30 -07001331 @Override
1332 public void addedSwitch(IOFSwitch sw) {
1333 if (!topologyReady) {
1334 sw.clearAllFlowMods();
1335 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001336
Ray Milkey269ffb92014-04-03 14:43:30 -07001337 flowCache.switchConnected(sw);
1338 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001339
Ray Milkey269ffb92014-04-03 14:43:30 -07001340 @Override
1341 public void removedSwitch(IOFSwitch sw) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001342 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001343 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001344
Ray Milkey269ffb92014-04-03 14:43:30 -07001345 @Override
1346 public void switchPortChanged(Long switchId) {
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 String getName() {
1352 return "BgpRoute";
1353 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001354
Ray Milkey269ffb92014-04-03 14:43:30 -07001355 /*
1356 * IConfigInfoService methods
1357 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001358
Ray Milkey269ffb92014-04-03 14:43:30 -07001359 @Override
1360 public boolean isInterfaceAddress(InetAddress address) {
1361 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1362 return (intf != null && intf.getIpAddress().equals(address));
1363 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001364
Ray Milkey269ffb92014-04-03 14:43:30 -07001365 @Override
1366 public boolean inConnectedNetwork(InetAddress address) {
1367 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1368 return (intf != null && !intf.getIpAddress().equals(address));
1369 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001370
Ray Milkey269ffb92014-04-03 14:43:30 -07001371 @Override
1372 public boolean fromExternalNetwork(long inDpid, short inPort) {
1373 for (Interface intf : interfaces.values()) {
1374 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1375 return true;
1376 }
1377 }
1378 return false;
1379 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001380
Ray Milkey269ffb92014-04-03 14:43:30 -07001381 @Override
1382 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1383 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1384 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001385
Ray Milkey269ffb92014-04-03 14:43:30 -07001386 @Override
1387 public boolean hasLayer3Configuration() {
1388 return !interfaces.isEmpty();
1389 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001390
Ray Milkey269ffb92014-04-03 14:43:30 -07001391 @Override
1392 public MACAddress getRouterMacAddress() {
1393 return bgpdMacAddress;
1394 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001395
Ray Milkey269ffb92014-04-03 14:43:30 -07001396 @Override
1397 public short getVlan() {
1398 return vlan;
1399 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001400}