blob: a1258ffde08b16020352547d0abbf1c3cf1a3836 [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 Milkey269ffb92014-04-03 14:43:30 -070079 private final static 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
521 SwitchPort dstPort = new SwitchPort();
522 dstPort.setDpid(new Dpid(egressInterface.getDpid()));
523 dstPort.setPort(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
543 SwitchPort srcPort = new SwitchPort();
544 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
545 srcPort.setPort(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();
554 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
555 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
Ray Milkey269ffb92014-04-03 14:43:30 -0700629 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
630 for (FlowId flowId : flowIds) {
631 // TODO: Delete the flow by using the new Path Intent framework
632 /*
633 if (log.isTraceEnabled()) {
634 //Trace the flow status by flowPath in the switch before deleting it
635 log.trace("Pushing a DELETE flow mod to flowPath : {}",
636 flowManagerService.getFlow(flowId).toString());
637 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700638
Ray Milkey269ffb92014-04-03 14:43:30 -0700639 if( flowManagerService.deleteFlow(flowId))
640 {
641 log.debug("Successfully deleted FlowId: {}",flowId);
642 }
643 else
644 {
645 log.debug("Failed to delete FlowId: {}",flowId);
646 }
647 */
648 }
649 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700650
Ray Milkey269ffb92014-04-03 14:43:30 -0700651 // TODO need to record the path and then delete here
652 private void deletePath(Path path) {
653 log.debug("Deleting flows for path to {}",
654 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700655
Ray Milkey269ffb92014-04-03 14:43:30 -0700656 // TODO need update
657 /*for (PushedFlowMod pfm : path.getFlowMods()) {
658 if (log.isTraceEnabled()) {
659 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
660 new Object[] {HexString.toHexString(pfm.getDpid()),
661 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
662 });
663 }
pingping-linba5c52f2014-02-11 16:52:01 -0800664
Ray Milkey269ffb92014-04-03 14:43:30 -0700665 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
666 }*/
667 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700668
669
Ray Milkey269ffb92014-04-03 14:43:30 -0700670 //TODO test next-hop changes
671 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800672
Ray Milkey269ffb92014-04-03 14:43:30 -0700673 /**
674 * On startup, we need to calculate a full mesh of paths between all gateway
675 * switches
676 */
677 private void setupFullMesh() {
678 //For each border router, calculate and install a path from every other
679 //border switch to said border router. However, don't install the entry
680 //in to the first hop switch, as we need to install an entry to rewrite
681 //for each prefix received. This will be done later when prefixes have
682 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700683
Ray Milkey269ffb92014-04-03 14:43:30 -0700684 for (BgpPeer peer : bgpPeers.values()) {
685 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700686
Ray Milkey269ffb92014-04-03 14:43:30 -0700687 //We know there's not already a Path here pushed, because this is
688 //called before all other routing
689 Path path = new Path(peerInterface, peer.getIpAddress());
690 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700691
Ray Milkey269ffb92014-04-03 14:43:30 -0700692 //See if we know the MAC address of the peer. If not we can't
693 //do anything until we learn it
694 // TODO: Fix the code below after deviceStorage was removed
695 MACAddress macAddress = null;
696 /*
697 IDeviceObject nextHopDevice =
698 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800699
Ray Milkey269ffb92014-04-03 14:43:30 -0700700 if(nextHopDevice == null){
701 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
702 //Put in the pending paths list first
703 pathsWaitingOnArp.put(peer.getIpAddress(), path);
704 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
705 continue;
706 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700707
Ray Milkey269ffb92014-04-03 14:43:30 -0700708 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
709 */
pingping-linba5c52f2014-02-11 16:52:01 -0800710
Ray Milkey269ffb92014-04-03 14:43:30 -0700711 if (macAddress == null) {
712 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
713 //Put in the pending paths list first
714 pathsWaitingOnArp.put(peer.getIpAddress(), path);
715 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
716 continue;
717 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700718
Ray Milkey269ffb92014-04-03 14:43:30 -0700719 //If we know the MAC, lets go ahead and push the paths to this peer
720 calculateAndPushPath(path, macAddress);
721 }
722 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700723
Ray Milkey269ffb92014-04-03 14:43:30 -0700724 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
725 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700726
Ray Milkey269ffb92014-04-03 14:43:30 -0700727 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
728 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800729
Ray Milkey269ffb92014-04-03 14:43:30 -0700730 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800731
Ray Milkey269ffb92014-04-03 14:43:30 -0700732 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800733
Ray Milkey269ffb92014-04-03 14:43:30 -0700734 // Set flowPath FlowPathType and FlowPathUserState
735 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
736 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800737
Ray Milkey269ffb92014-04-03 14:43:30 -0700738 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
739 FlowPathFlags flowPathFlags = new FlowPathFlags();
740 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
741 flowPath.setFlowPathFlags(flowPathFlags);
742
743 // Create the DataPath object: dstSwitchPort
744 SwitchPort dstPort = new SwitchPort();
745 dstPort.setDpid(new Dpid(dstInterface.getDpid()));
746 dstPort.setPort(new Port(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800747
Ray Milkey269ffb92014-04-03 14:43:30 -0700748 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800749
Ray Milkey269ffb92014-04-03 14:43:30 -0700750 if (dstInterface.equals(srcInterface)) {
751 continue;
752 }
pingping-linba5c52f2014-02-11 16:52:01 -0800753
Ray Milkey269ffb92014-04-03 14:43:30 -0700754 // Create flowPath FlowId
755 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800756
Ray Milkey269ffb92014-04-03 14:43:30 -0700757 // Create the DataPath object: srcSwitchPort
758 SwitchPort srcPort = new SwitchPort();
759 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
760 srcPort.setPort(new Port(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800761
Ray Milkey269ffb92014-04-03 14:43:30 -0700762 DataPath dataPath = new DataPath();
763 dataPath.setSrcPort(srcPort);
764 dataPath.setDstPort(dstPort);
765 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800766
Ray Milkey269ffb92014-04-03 14:43:30 -0700767 // Create the Flow Path Match condition(s)
768 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
769 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
770 flowEntryMatch.enableDstMac(dstMacAddress);
771 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800772
Ray Milkey269ffb92014-04-03 14:43:30 -0700773 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
774 // Shortest Path Flow, and is always the last action for the Flow Entries
775 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
776 // TODO: Add the flow by using the new Path Intent framework
777 /*
778 if (flowManagerService.addFlow(flowPath) == null) {
779 log.error("Failed to set up MAC based forwarding path to {}, {}",
780 path.getDstIpAddress().getHostAddress(),dstMacAddress);
781 }
782 else {
783 log.debug("Successfully set up MAC based forwarding path to {}, {}",
784 path.getDstIpAddress().getHostAddress(),dstMacAddress);
785 }
786 */
787 }
788 }
pingping-linba5c52f2014-02-11 16:52:01 -0800789
Ray Milkey269ffb92014-04-03 14:43:30 -0700790 /**
Jonathan Hart938a0152014-04-07 18:27:31 -0700791 * Proactively install all BGP traffic paths from BGP host attachment point
Ray Milkey269ffb92014-04-03 14:43:30 -0700792 * in SDN network to all the virtual gateways to BGP peers in other networks
793 */
794 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200795
Ray Milkey269ffb92014-04-03 14:43:30 -0700796 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800797
Ray Milkey269ffb92014-04-03 14:43:30 -0700798 FlowPath flowPath = new FlowPath();
799 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800800
Ray Milkey269ffb92014-04-03 14:43:30 -0700801 // Set flowPath FlowPathType and FlowPathUserState
802 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
803 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800804
Ray Milkey269ffb92014-04-03 14:43:30 -0700805 // Install flow paths between BGPd and its peers
806 // There is no need to set the FlowPathFlags
807 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800808
Ray Milkey269ffb92014-04-03 14:43:30 -0700809 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
pingping-linba5c52f2014-02-11 16:52:01 -0800810
Ray Milkey269ffb92014-04-03 14:43:30 -0700811 // Create the Flow Path Match condition(s)
812 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
813 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
pingping-linba5c52f2014-02-11 16:52:01 -0800814
Ray Milkey269ffb92014-04-03 14:43:30 -0700815 // Match both source address and dest address
816 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress() + "/32");
817 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800818
Ray Milkey269ffb92014-04-03 14:43:30 -0700819 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress().getHostAddress() + "/32");
820 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800821
Ray Milkey269ffb92014-04-03 14:43:30 -0700822 // Match TCP protocol
823 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800824
Ray Milkey269ffb92014-04-03 14:43:30 -0700825 // Match destination TCP port
826 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
827 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800828
Ray Milkey269ffb92014-04-03 14:43:30 -0700829 /**
830 * Create the DataPath: BGP -> BGP peer
831 */
832 // Flow path for src-TCP-port
833 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800834
Ray Milkey269ffb92014-04-03 14:43:30 -0700835 SwitchPort srcPort = new SwitchPort();
836 srcPort.setDpid(bgpdAttachmentPoint.dpid());
837 srcPort.setPort(bgpdAttachmentPoint.port());
838 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800839
Ray Milkey269ffb92014-04-03 14:43:30 -0700840 SwitchPort dstPort = new SwitchPort();
841 dstPort.setDpid(new Dpid(peerInterface.getDpid()));
842 dstPort.setPort(new Port(peerInterface.getSwitchPort().port()));
843 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800844
Ray Milkey269ffb92014-04-03 14:43:30 -0700845 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800846
Ray Milkey269ffb92014-04-03 14:43:30 -0700847 // TODO: Add the flow by using the new Path Intent framework
848 /*
849 if (flowManagerService.addFlow(flowPath) == null) {
850 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
851 bgpPeer.getIpAddress().getHostAddress());
852 }
853 else {
854 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
855 bgpPeer.getIpAddress().getHostAddress());
856 }
857 */
pingping-linba5c52f2014-02-11 16:52:01 -0800858
Ray Milkey269ffb92014-04-03 14:43:30 -0700859 // Disable dst-TCP-port, and set src-TCP-port
860 flowEntryMatch.disableDstTcpUdpPort();
861 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
862 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800863
Ray Milkey269ffb92014-04-03 14:43:30 -0700864 // Create a new FlowId
865 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800866
Ray Milkey269ffb92014-04-03 14:43:30 -0700867 // TODO: Add the flow by using the new Path Intent framework
868 /*
869 if (flowManagerService.addFlow(flowPath) == null) {
870 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
871 bgpPeer.getIpAddress().getHostAddress());
872 }
873 else {
874 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
875 bgpPeer.getIpAddress().getHostAddress());
876 }
877 */
pingping-linba5c52f2014-02-11 16:52:01 -0800878
Ray Milkey269ffb92014-04-03 14:43:30 -0700879 /**
880 * Create the DataPath: BGP <-BGP peer
881 */
882 // Reversed BGP flow path for src-TCP-port
883 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800884
Ray Milkey2476cac2014-04-08 11:03:21 -0700885 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800886
Ray Milkey2476cac2014-04-08 11:03:21 -0700887 SwitchPort reverseDstPort = new SwitchPort();
888 reverseDstPort.setDpid(bgpdAttachmentPoint.dpid());
889 reverseDstPort.setPort(bgpdAttachmentPoint.port());
890 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800891
Ray Milkey2476cac2014-04-08 11:03:21 -0700892 SwitchPort reverseSrcPort = new SwitchPort();
893 reverseSrcPort.setDpid(new Dpid(peerInterface.getDpid()));
894 reverseSrcPort.setPort(new Port(peerInterface.getSwitchPort().port()));
895 reverseDataPath.setSrcPort(reverseSrcPort);
896 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800897
Jonathan Hart938a0152014-04-07 18:27:31 -0700898 // Reverse the dst IP and src IP addresses
Ray Milkey269ffb92014-04-03 14:43:30 -0700899 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
900 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
901 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800902
Ray Milkey269ffb92014-04-03 14:43:30 -0700903 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800904
Ray Milkey269ffb92014-04-03 14:43:30 -0700905 // TODO: Add the flow by using the new Path Intent framework
906 /*
907 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800908
Ray Milkey269ffb92014-04-03 14:43:30 -0700909 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
910 bgpPeer.getIpAddress().getHostAddress());
911 }
912 else {
913 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
914 bgpPeer.getIpAddress().getHostAddress());
915 }
916 */
pingping-linba5c52f2014-02-11 16:52:01 -0800917
Ray Milkey269ffb92014-04-03 14:43:30 -0700918 // Reversed BGP flow path for dst-TCP-port
919 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800920
Ray Milkey269ffb92014-04-03 14:43:30 -0700921 // Disable src-TCP-port, and set the dst-TCP-port
922 flowEntryMatch.disableSrcTcpUdpPort();
923 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
924 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800925
Ray Milkey269ffb92014-04-03 14:43:30 -0700926 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800927
Ray Milkey269ffb92014-04-03 14:43:30 -0700928 // TODO: Add the flow by using the new Path Intent framework
929 /*
930 if (flowManagerService.addFlow(flowPath) == null) {
931 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
932 bgpPeer.getIpAddress().getHostAddress());
933 }
934 else {
935 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
936 bgpPeer.getIpAddress().getHostAddress());
937 }
938 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700939
Ray Milkey269ffb92014-04-03 14:43:30 -0700940 /**
941 * ICMP paths between BGPd and its peers
942 */
Jonathan Hart938a0152014-04-07 18:27:31 -0700943 // match ICMP protocol BGP <- Peer
Ray Milkey269ffb92014-04-03 14:43:30 -0700944 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800945
Ray Milkey269ffb92014-04-03 14:43:30 -0700946 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
947 flowEntryMatch.disableSrcTcpUdpPort();
948 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -0800949
Ray Milkey269ffb92014-04-03 14:43:30 -0700950 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800951
Ray Milkey2476cac2014-04-08 11:03:21 -0700952 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800953
Ray Milkey269ffb92014-04-03 14:43:30 -0700954 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800955
Ray Milkey269ffb92014-04-03 14:43:30 -0700956 // TODO: Add the flow by using the new Path Intent framework
957 /*
958 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800959
Ray Milkey269ffb92014-04-03 14:43:30 -0700960 log.error("Failed to set up ICMP path BGP <- Peer {}",
961 bgpPeer.getIpAddress().getHostAddress());
962 }
963 else {
964 log.debug("Successfully set up ICMP path BGP <- Peer {}",
965 bgpPeer.getIpAddress().getHostAddress());
966 }
967 */
pingping-linba5c52f2014-02-11 16:52:01 -0800968
Jonathan Hart938a0152014-04-07 18:27:31 -0700969 // match ICMP protocol BGP -> Peer
Ray Milkey269ffb92014-04-03 14:43:30 -0700970 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800971
Ray Milkey269ffb92014-04-03 14:43:30 -0700972 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
973 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
974 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800975
Ray Milkey269ffb92014-04-03 14:43:30 -0700976 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800977
Ray Milkey269ffb92014-04-03 14:43:30 -0700978 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800979
Ray Milkey269ffb92014-04-03 14:43:30 -0700980 // TODO: Add the flow by using the new Path Intent framework
981 /*
982 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800983
Ray Milkey269ffb92014-04-03 14:43:30 -0700984 log.error("Failed to set up ICMP path BGP -> Peer {}",
985 bgpPeer.getIpAddress().getHostAddress());
986 }
987 else {
988 log.debug("Successfully set up ICMP path BGP -> Peer {}",
989 bgpPeer.getIpAddress().getHostAddress());
990 }
991 */
992 }
993 }
pingping-linba5c52f2014-02-11 16:52:01 -0800994
Ray Milkey269ffb92014-04-03 14:43:30 -0700995 @Override
996 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
997 log.debug("Received ARP response: {} => {}",
998 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700999
Ray Milkey269ffb92014-04-03 14:43:30 -07001000 /*
1001 * We synchronize on this to prevent changes to the ptree while we're pushing
1002 * flows to the switches. If the ptree changes, the ptree and switches
1003 * could get out of sync.
1004 */
1005 synchronized (this) {
1006 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001007
Ray Milkey269ffb92014-04-03 14:43:30 -07001008 if (path != null) {
1009 log.debug("Pushing path to {} at {} on {}", new Object[]{
1010 path.getDstIpAddress().getHostAddress(), macAddress,
1011 path.getDstInterface().getSwitchPort()});
Jonathan Hart938a0152014-04-07 18:27:31 -07001012 // These paths should always be to BGP peers. Paths to non-peers are
1013 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -07001014 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001015 // A path already got pushed to this endpoint while we were waiting
1016 // for ARP. We'll copy over the permanent attribute if it is set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -07001017 if (path.isPermanent()) {
1018 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1019 }
1020 } else {
1021 calculateAndPushPath(path, macAddress);
1022 pushedPaths.put(path.getDstIpAddress(), path);
1023 }
1024 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001025
Ray Milkey269ffb92014-04-03 14:43:30 -07001026 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001027
Ray Milkey269ffb92014-04-03 14:43:30 -07001028 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001029 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001030
Ray Milkey269ffb92014-04-03 14:43:30 -07001031 RibEntry rib = ptree.lookup(update.getPrefix());
1032 if (rib != null && rib.equals(update.getRibEntry())) {
1033 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1034 rib.getNextHop().getHostAddress());
Jonathan Hart938a0152014-04-07 18:27:31 -07001035 // We only push prefix flows if the prefix is still in the ptree
1036 // and the next hop is the same as our update. The prefix could
1037 // have been removed while we were waiting for the ARP, or the
1038 // next hop could have changed.
Ray Milkey269ffb92014-04-03 14:43:30 -07001039 _processRibAdd(update);
1040 } else {
1041 log.debug("Received ARP response, but {},{} is no longer in ptree",
1042 update.getPrefix(), update.getRibEntry());
1043 }
1044 }
1045 }
1046 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001047
Jonathan Hart938a0152014-04-07 18:27:31 -07001048 // TODO wait the priority module of the flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001049 private void setupArpFlows() {
1050 OFMatch match = new OFMatch();
1051 match.setDataLayerType(Ethernet.TYPE_ARP);
1052 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001053
Ray Milkey269ffb92014-04-03 14:43:30 -07001054 OFFlowMod fm = new OFFlowMod();
1055 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001056
Ray Milkey269ffb92014-04-03 14:43:30 -07001057 OFActionOutput action = new OFActionOutput();
1058 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1059 action.setMaxLength((short) 0xffff);
1060 List<OFAction> actions = new ArrayList<OFAction>(1);
1061 actions.add(action);
1062 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001063
Ray Milkey269ffb92014-04-03 14:43:30 -07001064 fm.setIdleTimeout((short) 0)
1065 .setHardTimeout((short) 0)
1066 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1067 .setCookie(0)
1068 .setCommand(OFFlowMod.OFPFC_ADD)
1069 .setPriority(ARP_PRIORITY)
1070 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001071
Ray Milkey269ffb92014-04-03 14:43:30 -07001072 for (String strdpid : switches) {
1073 flowCache.write(HexString.toLong(strdpid), fm);
1074 }
1075 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001076
Jonathan Hart938a0152014-04-07 18:27:31 -07001077 // TODO need update, waiting for the priority feature from flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001078 private void setupDefaultDropFlows() {
1079 OFFlowMod fm = new OFFlowMod();
1080 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -07001081 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001082
Ray Milkey269ffb92014-04-03 14:43:30 -07001083 fm.setIdleTimeout((short) 0)
1084 .setHardTimeout((short) 0)
1085 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1086 .setCookie(0)
1087 .setCommand(OFFlowMod.OFPFC_ADD)
1088 .setPriority((short) 0)
1089 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001090
Ray Milkey269ffb92014-04-03 14:43:30 -07001091 OFFlowMod fmLLDP;
1092 OFFlowMod fmBDDP;
1093 try {
1094 fmLLDP = fm.clone();
1095 fmBDDP = fm.clone();
1096 } catch (CloneNotSupportedException e1) {
1097 log.error("Error cloning flow mod", e1);
1098 return;
1099 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001100
Ray Milkey269ffb92014-04-03 14:43:30 -07001101 OFMatch matchLLDP = new OFMatch();
1102 matchLLDP.setDataLayerType((short) 0x88cc);
1103 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1104 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001105
Ray Milkey269ffb92014-04-03 14:43:30 -07001106 OFMatch matchBDDP = new OFMatch();
1107 matchBDDP.setDataLayerType((short) 0x8942);
1108 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1109 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001110
Ray Milkey269ffb92014-04-03 14:43:30 -07001111 OFActionOutput action = new OFActionOutput();
1112 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1113 action.setMaxLength((short) 0xffff);
1114 List<OFAction> actions = new ArrayList<OFAction>(1);
1115 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001116
Ray Milkey269ffb92014-04-03 14:43:30 -07001117 fmLLDP.setActions(actions);
1118 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001119
Ray Milkey269ffb92014-04-03 14:43:30 -07001120 fmLLDP.setPriority(ARP_PRIORITY);
1121 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1122 fmBDDP.setPriority(ARP_PRIORITY);
1123 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001124
Ray Milkey269ffb92014-04-03 14:43:30 -07001125 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1126 flowModList.add(fm);
1127 flowModList.add(fmLLDP);
1128 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001129
Ray Milkey269ffb92014-04-03 14:43:30 -07001130 for (String strdpid : switches) {
1131 flowCache.write(HexString.toLong(strdpid), flowModList);
1132 }
1133 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001134
Ray Milkey269ffb92014-04-03 14:43:30 -07001135 private void beginRouting() {
1136 log.debug("Topology is now ready, beginning routing function");
1137 // TODO: Fix for the new Topology Network Graph
1138 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001139
Ray Milkey269ffb92014-04-03 14:43:30 -07001140 // Wait Pavlin's API. We need the following functions.
1141 /*setupArpFlows();
1142 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001143
Ray Milkey269ffb92014-04-03 14:43:30 -07001144 setupBgpPaths();
1145 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001146
Ray Milkey269ffb92014-04-03 14:43:30 -07001147 //Suppress link discovery on external-facing router ports
1148 for (Interface intf : interfaces.values()) {
1149 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1150 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001151
Ray Milkey269ffb92014-04-03 14:43:30 -07001152 bgpUpdatesExecutor.execute(new Runnable() {
1153 @Override
1154 public void run() {
1155 doUpdatesThread();
1156 }
1157 });
1158 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001159
Jonathan Hart938a0152014-04-07 18:27:31 -07001160 // Before inserting the paths for BGP traffic, we should check whether
1161 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001162 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001163 // TODO: Fix the code below after topoSwitchSerice was removed
1164 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001165 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001166
Ray Milkey269ffb92014-04-03 14:43:30 -07001167 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1168 getActiveSwitches().iterator();
1169 while(activeSwitches.hasNext())
1170 {
1171 ISwitchObject switchObject = activeSwitches.next();
1172 if (switchObject.getDPID().equals(dpid)) {
1173 break;
1174 }
1175 if(activeSwitches.hasNext() == false) {
1176 log.debug("Not all switches are here yet");
1177 return;
1178 }
1179 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001180 }
1181 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001182 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001183 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001184
Jonathan Hart938a0152014-04-07 18:27:31 -07001185 // Actually we only need to go half way round to verify full mesh connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001186 private void checkTopologyReady() {
1187 for (Interface dstInterface : interfaces.values()) {
1188 for (Interface srcInterface : interfaces.values()) {
1189 if (dstInterface.equals(srcInterface)) {
1190 continue;
1191 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001192
Ray Milkey269ffb92014-04-03 14:43:30 -07001193 // TODO: Fix for the new Topology Network Graph
1194 /*
1195 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1196 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001197
Ray Milkey269ffb92014-04-03 14:43:30 -07001198 if (shortestPath == null){
1199 log.debug("Shortest path between {} and {} not found",
1200 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1201 return;
1202 }
1203 */
1204 }
1205 }
1206 topologyReady = true;
1207 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001208
Ray Milkey269ffb92014-04-03 14:43:30 -07001209 private void checkStatus() {
1210 if (!switchesConnected) {
1211 checkSwitchesConnected();
1212 }
1213 boolean oldTopologyReadyStatus = topologyReady;
1214 if (switchesConnected && !topologyReady) {
1215 checkTopologyReady();
1216 }
1217 if (!oldTopologyReadyStatus && topologyReady) {
1218 beginRouting();
1219 }
1220 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001221
Ray Milkey269ffb92014-04-03 14:43:30 -07001222 private void doUpdatesThread() {
1223 boolean interrupted = false;
1224 try {
1225 while (true) {
1226 try {
1227 RibUpdate update = ribUpdates.take();
1228 switch (update.getOperation()) {
1229 case UPDATE:
1230 if (validateUpdate(update)) {
1231 processRibAdd(update);
1232 } else {
1233 log.debug("Rib UPDATE out of order: {} via {}",
1234 update.getPrefix(), update.getRibEntry().getNextHop());
1235 }
1236 break;
1237 case DELETE:
1238 if (validateUpdate(update)) {
1239 processRibDelete(update);
1240 } else {
1241 log.debug("Rib DELETE out of order: {} via {}",
1242 update.getPrefix(), update.getRibEntry().getNextHop());
1243 }
1244 break;
1245 }
1246 } catch (InterruptedException e) {
1247 log.debug("Interrupted while taking from updates queue", e);
1248 interrupted = true;
1249 } catch (Exception e) {
1250 log.debug("exception", e);
1251 }
1252 }
1253 } finally {
1254 if (interrupted) {
1255 Thread.currentThread().interrupt();
1256 }
1257 }
1258 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001259
Ray Milkey269ffb92014-04-03 14:43:30 -07001260 private boolean validateUpdate(RibUpdate update) {
1261 RibEntry newEntry = update.getRibEntry();
1262 RibEntry oldEntry = ptree.lookup(update.getPrefix());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001263
Ray Milkey269ffb92014-04-03 14:43:30 -07001264 //If there is no existing entry we must assume this is the most recent
1265 //update. However this might not always be the case as we might have a
1266 //POST then DELETE reordering.
1267 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1268 if (oldEntry == null) {
1269 return true;
1270 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001271
Ray Milkey269ffb92014-04-03 14:43:30 -07001272 // This handles the case where routes are gathered in the initial
1273 // request because they don't have sequence number info
1274 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1275 return true;
1276 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001277
Ray Milkey269ffb92014-04-03 14:43:30 -07001278 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1279 return true;
1280 } else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1281 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1282 return true;
1283 } else {
1284 return false;
1285 }
1286 } else {
1287 return false;
1288 }
1289 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001290
Ray Milkey269ffb92014-04-03 14:43:30 -07001291 // The code below should be reimplemented after removal of Floodlight's
1292 // ITopologyService API. It should be implemented on top of network graph
1293 // notifications. (It was pretty hacky anyway...)
1294 /*
1295 @Override
1296 public void topologyChanged() {
1297 if (topologyReady) {
1298 return;
1299 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001300
Ray Milkey269ffb92014-04-03 14:43:30 -07001301 boolean refreshNeeded = false;
1302 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1303 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1304 //We don't need to recalculate anything for just link updates
1305 //They happen very frequently
1306 refreshNeeded = true;
1307 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001308
Ray Milkey269ffb92014-04-03 14:43:30 -07001309 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001310
Ray Milkey269ffb92014-04-03 14:43:30 -07001311 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1312 synchronized (linkUpdates) {
1313 linkUpdates.add(ldu);
1314 }
1315 }
1316 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001317
Ray Milkey269ffb92014-04-03 14:43:30 -07001318 if (refreshNeeded && !topologyReady){
1319 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1320 }
1321 }
1322 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001323
Ray Milkey269ffb92014-04-03 14:43:30 -07001324 @Override
1325 public void addedSwitch(IOFSwitch sw) {
1326 if (!topologyReady) {
1327 sw.clearAllFlowMods();
1328 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001329
Ray Milkey269ffb92014-04-03 14:43:30 -07001330 flowCache.switchConnected(sw);
1331 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001332
Ray Milkey269ffb92014-04-03 14:43:30 -07001333 @Override
1334 public void removedSwitch(IOFSwitch sw) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001335 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001336 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001337
Ray Milkey269ffb92014-04-03 14:43:30 -07001338 @Override
1339 public void switchPortChanged(Long switchId) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001340 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001341 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001342
Ray Milkey269ffb92014-04-03 14:43:30 -07001343 @Override
1344 public String getName() {
1345 return "BgpRoute";
1346 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001347
Ray Milkey269ffb92014-04-03 14:43:30 -07001348 /*
1349 * IConfigInfoService methods
1350 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001351
Ray Milkey269ffb92014-04-03 14:43:30 -07001352 @Override
1353 public boolean isInterfaceAddress(InetAddress address) {
1354 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1355 return (intf != null && intf.getIpAddress().equals(address));
1356 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001357
Ray Milkey269ffb92014-04-03 14:43:30 -07001358 @Override
1359 public boolean inConnectedNetwork(InetAddress address) {
1360 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1361 return (intf != null && !intf.getIpAddress().equals(address));
1362 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001363
Ray Milkey269ffb92014-04-03 14:43:30 -07001364 @Override
1365 public boolean fromExternalNetwork(long inDpid, short inPort) {
1366 for (Interface intf : interfaces.values()) {
1367 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1368 return true;
1369 }
1370 }
1371 return false;
1372 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001373
Ray Milkey269ffb92014-04-03 14:43:30 -07001374 @Override
1375 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1376 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1377 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001378
Ray Milkey269ffb92014-04-03 14:43:30 -07001379 @Override
1380 public boolean hasLayer3Configuration() {
1381 return !interfaces.isEmpty();
1382 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001383
Ray Milkey269ffb92014-04-03 14:43:30 -07001384 @Override
1385 public MACAddress getRouterMacAddress() {
1386 return bgpdMacAddress;
1387 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001388
Ray Milkey269ffb92014-04-03 14:43:30 -07001389 @Override
1390 public short getVlan() {
1391 return vlan;
1392 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001393}