blob: 3c588f28b9a373fb831c0f7e6e91c03697521554 [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 Milkey269ffb92014-04-03 14:43:30 -070094 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
95 //the controller/OS should hand out cookie IDs to prevent conflicts.
Ray Milkey2476cac2014-04-08 11:03:21 -070096 private static final long APP_COOKIE = 0xa0000000000000L;
Ray Milkey269ffb92014-04-03 14:43:30 -070097 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Ray Milkey2476cac2014-04-08 11:03:21 -070098 private static final long L2_FWD_COOKIE = APP_COOKIE + 1;
Ray Milkey269ffb92014-04-03 14:43:30 -070099 //Cookie for flows in ingress switches that rewrite the MAC address
Ray Milkey2476cac2014-04-08 11:03:21 -0700100 private static final long MAC_RW_COOKIE = APP_COOKIE + 2;
Ray Milkey269ffb92014-04-03 14:43:30 -0700101 //Cookie for flows that setup BGP paths
Ray Milkey2476cac2014-04-08 11:03:21 -0700102 private static final long BGP_COOKIE = APP_COOKIE + 3;
Ray Milkey269ffb92014-04-03 14:43:30 -0700103 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
104 //need to be higher priority than this otherwise the rewrite may not get done
Ray Milkey2476cac2014-04-08 11:03:21 -0700105 private static final short SDNIP_PRIORITY = 10;
106 private static final short ARP_PRIORITY = 20;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700107
Ray Milkey2476cac2014-04-08 11:03:21 -0700108 private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700109
Ray Milkey2476cac2014-04-08 11:03:21 -0700110 private static final int TOPO_DETECTION_WAIT = 2; //seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700111
Ray Milkey269ffb92014-04-03 14:43:30 -0700112 //Configuration stuff
113 private List<String> switches;
114 private Map<String, Interface> interfaces;
115 private Map<InetAddress, BgpPeer> bgpPeers;
116 private SwitchPort bgpdAttachmentPoint;
117 private MACAddress bgpdMacAddress;
118 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700119
Ray Milkey269ffb92014-04-03 14:43:30 -0700120 //True when all switches have connected
121 private volatile boolean switchesConnected = false;
122 //True when we have a full mesh of shortest paths between gateways
123 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200124
Ray Milkey269ffb92014-04-03 14:43:30 -0700125 private ArrayList<LDUpdate> linkUpdates;
126 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700127
Ray Milkey269ffb92014-04-03 14:43:30 -0700128 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700129
Ray Milkey269ffb92014-04-03 14:43:30 -0700130 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700131
Ray Milkey269ffb92014-04-03 14:43:30 -0700132 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700133
Ray Milkey269ffb92014-04-03 14:43:30 -0700134 private Map<InetAddress, Path> pushedPaths;
135 private Map<Prefix, Path> prefixToPath;
136 // private Multimap<Prefix, PushedFlowMod> pushedFlows;
137 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700138
Ray Milkey269ffb92014-04-03 14:43:30 -0700139 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700140
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 // TODO: Fix for the new Topology Network Graph
142 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700143
Ray Milkey269ffb92014-04-03 14:43:30 -0700144 private class TopologyChangeDetector implements Runnable {
145 @Override
146 public void run() {
147 log.debug("Running topology change detection task");
148 synchronized (linkUpdates) {
149 //This is the model the REST API uses to retrieve network graph info
150 // TODO: Fix the code below after topoLinkService was removed
151 /*
152 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700153
Ray Milkey269ffb92014-04-03 14:43:30 -0700154 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700155
Ray Milkey269ffb92014-04-03 14:43:30 -0700156 Iterator<LDUpdate> it = linkUpdates.iterator();
157 while (it.hasNext()){
158 LDUpdate ldu = it.next();
159 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
160 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700161
Ray Milkey269ffb92014-04-03 14:43:30 -0700162 if (activeLinks.contains(l)){
163 it.remove();
164 }
165 }
166 */
167 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700168
Ray Milkey269ffb92014-04-03 14:43:30 -0700169 if (!topologyReady) {
170 if (linkUpdates.isEmpty()) {
171 //All updates have been seen in network map.
172 //We can check if topology is ready
173 log.debug("No known changes outstanding. Checking topology now");
174 checkStatus();
175 } else {
176 //We know of some link updates that haven't propagated to the database yet
177 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
178 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
179 }
180 }
181 }
182 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700183
Ray Milkey269ffb92014-04-03 14:43:30 -0700184 private void readConfiguration(String configFilename) {
185 File gatewaysFile = new File(configFilename);
186 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700187
Ray Milkey269ffb92014-04-03 14:43:30 -0700188 try {
189 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700190
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 switches = config.getSwitches();
192 interfaces = new HashMap<String, Interface>();
193 for (Interface intf : config.getInterfaces()) {
194 interfaces.put(intf.getName(), intf);
195 }
196 bgpPeers = new HashMap<InetAddress, BgpPeer>();
197 for (BgpPeer peer : config.getPeers()) {
198 bgpPeers.put(peer.getIpAddress(), peer);
199 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700200
Ray Milkey269ffb92014-04-03 14:43:30 -0700201 bgpdAttachmentPoint = new SwitchPort(
202 new Dpid(config.getBgpdAttachmentDpid()),
203 new Port(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700204
Ray Milkey269ffb92014-04-03 14:43:30 -0700205 bgpdMacAddress = config.getBgpdMacAddress();
206 vlan = config.getVlan();
207 } catch (JsonParseException e) {
208 log.error("Error in JSON file", e);
209 System.exit(1);
210 } catch (JsonMappingException e) {
211 log.error("Error in JSON file", e);
212 System.exit(1);
213 } catch (IOException e) {
214 log.error("Error reading JSON file", e);
215 System.exit(1);
216 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700217
Ray Milkey269ffb92014-04-03 14:43:30 -0700218 //Populate the interface Patricia Trie
219 for (Interface intf : interfaces.values()) {
220 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
221 interfacePtrie.put(prefix, intf);
222 }
223 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700224
Ray Milkey269ffb92014-04-03 14:43:30 -0700225 @Override
226 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
227 Collection<Class<? extends IFloodlightService>> l
228 = new ArrayList<Class<? extends IFloodlightService>>();
229 l.add(IBgpRouteService.class);
230 l.add(IConfigInfoService.class);
231 return l;
232 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700233
Ray Milkey269ffb92014-04-03 14:43:30 -0700234 @Override
235 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
236 Map<Class<? extends IFloodlightService>, IFloodlightService> m
237 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
238 m.put(IBgpRouteService.class, this);
239 m.put(IConfigInfoService.class, this);
240 return m;
241 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800242
Ray Milkey269ffb92014-04-03 14:43:30 -0700243 @Override
244 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
245 Collection<Class<? extends IFloodlightService>> l
246 = new ArrayList<Class<? extends IFloodlightService>>();
247 l.add(IFloodlightProviderService.class);
248 l.add(IRestApiService.class);
249 return l;
250 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700251
Ray Milkey269ffb92014-04-03 14:43:30 -0700252 @Override
253 public void init(FloodlightModuleContext context)
254 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700255
Ray Milkey269ffb92014-04-03 14:43:30 -0700256 ptree = new PatriciaTrie<RibEntry>(32);
257 interfacePtrie = new PatriciaTrie<Interface>(32);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700258
Ray Milkey269ffb92014-04-03 14:43:30 -0700259 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700260
Ray Milkey269ffb92014-04-03 14:43:30 -0700261 // Register floodlight provider and REST handler.
262 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
263 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
264 restApi = context.getServiceImpl(IRestApiService.class);
265 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800266
Ray Milkey269ffb92014-04-03 14:43:30 -0700267 linkUpdates = new ArrayList<LDUpdate>();
268 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
269 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700270
Ray Milkey269ffb92014-04-03 14:43:30 -0700271 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
272 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
273 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700274
Ray Milkey269ffb92014-04-03 14:43:30 -0700275 pushedPaths = new HashMap<InetAddress, Path>();
276 prefixToPath = new HashMap<Prefix, Path>();
277// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
278 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700279
Ray Milkey269ffb92014-04-03 14:43:30 -0700280 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700281
Ray Milkey269ffb92014-04-03 14:43:30 -0700282 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
283 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700284
Ray Milkey269ffb92014-04-03 14:43:30 -0700285 //Read in config values
286 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
287 if (bgpdRestIp == null) {
288 log.error("BgpdRestIp property not found in config file");
289 System.exit(1);
290 } else {
291 log.info("BgpdRestIp set to {}", bgpdRestIp);
292 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700293
Ray Milkey269ffb92014-04-03 14:43:30 -0700294 routerId = context.getConfigParams(this).get("RouterId");
295 if (routerId == null) {
296 log.error("RouterId property not found in config file");
297 System.exit(1);
298 } else {
299 log.info("RouterId set to {}", routerId);
300 }
pingping-linba5c52f2014-02-11 16:52:01 -0800301
Ray Milkey269ffb92014-04-03 14:43:30 -0700302 String configFilenameParameter = context.getConfigParams(this).get("configfile");
303 if (configFilenameParameter != null) {
304 configFilename = configFilenameParameter;
305 }
306 log.debug("Config file set to {}", configFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700307
Ray Milkey269ffb92014-04-03 14:43:30 -0700308 readConfiguration(configFilename);
309 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700310
Ray Milkey269ffb92014-04-03 14:43:30 -0700311 @Override
312 public void startUp(FloodlightModuleContext context) {
313 restApi.addRestletRoutable(new BgpRouteWebRoutable());
314 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800315
Ray Milkey269ffb92014-04-03 14:43:30 -0700316 //Retrieve the RIB from BGPd during startup
317 retrieveRib();
318 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800319
Ray Milkey269ffb92014-04-03 14:43:30 -0700320 @Override
321 public IPatriciaTrie<RibEntry> getPtree() {
322 return ptree;
323 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700324
Ray Milkey269ffb92014-04-03 14:43:30 -0700325 @Override
326 public void clearPtree() {
327 ptree = new PatriciaTrie<RibEntry>(32);
328 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700329
Ray Milkey269ffb92014-04-03 14:43:30 -0700330 @Override
331 public String getBGPdRestIp() {
332 return bgpdRestIp;
333 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700334
Ray Milkey269ffb92014-04-03 14:43:30 -0700335 @Override
336 public String getRouterId() {
337 return routerId;
338 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700339
Ray Milkey269ffb92014-04-03 14:43:30 -0700340 private void retrieveRib() {
341 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
342 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700343
Ray Milkey269ffb92014-04-03 14:43:30 -0700344 if (response.equals("")) {
345 return;
346 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700347
Ray Milkey269ffb92014-04-03 14:43:30 -0700348 response = response.replaceAll("\"", "'");
349 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
Ray Milkey2476cac2014-04-08 11:03:21 -0700350 JSONArray ribJsonArray = jsonObj.getJSONArray("rib");
351 String routerId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700352
Ray Milkey2476cac2014-04-08 11:03:21 -0700353 int size = ribJsonArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700354
Ray Milkey269ffb92014-04-03 14:43:30 -0700355 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700356
Ray Milkey269ffb92014-04-03 14:43:30 -0700357 for (int j = 0; j < size; j++) {
Ray Milkey2476cac2014-04-08 11:03:21 -0700358 JSONObject secondJsonObject = ribJsonArray.getJSONObject(j);
359 String prefix = secondJsonObject.getString("prefix");
360 String nexthop = secondJsonObject.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700361
Ray Milkey269ffb92014-04-03 14:43:30 -0700362 //insert each rib entry into the local rib;
363 String[] substring = prefix.split("/");
364 String prefix1 = substring[0];
365 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700366
Ray Milkey269ffb92014-04-03 14:43:30 -0700367 Prefix p;
368 try {
369 p = new Prefix(prefix1, Integer.valueOf(mask1));
370 } catch (NumberFormatException e) {
371 log.warn("Wrong mask format in RIB JSON: {}", mask1);
372 continue;
373 } catch (IllegalArgumentException e1) {
374 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
375 continue;
376 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700377
Ray Milkey2476cac2014-04-08 11:03:21 -0700378 RibEntry rib = new RibEntry(routerId, nexthop);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700379
Ray Milkey269ffb92014-04-03 14:43:30 -0700380 try {
381 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
382 } catch (InterruptedException e) {
383 log.debug("Interrupted while pushing onto update queue");
384 }
385 }
386 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700387
Ray Milkey269ffb92014-04-03 14:43:30 -0700388 @Override
389 public void newRibUpdate(RibUpdate update) {
390 try {
391 ribUpdates.put(update);
392 } catch (InterruptedException e) {
393 log.debug("Interrupted while putting on ribUpdates queue", e);
394 Thread.currentThread().interrupt();
395 }
396 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700397
Ray Milkey269ffb92014-04-03 14:43:30 -0700398 public synchronized void processRibAdd(RibUpdate update) {
399 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700400
Ray Milkey269ffb92014-04-03 14:43:30 -0700401 log.debug("Processing prefix add {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700402
Ray Milkey269ffb92014-04-03 14:43:30 -0700403 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700404
Ray Milkey269ffb92014-04-03 14:43:30 -0700405 if (rib != null && !rib.equals(update.getRibEntry())) {
406 //There was an existing nexthop for this prefix. This update supersedes that,
407 //so we need to remove the old flows for this prefix from the switches
408 _processDeletePrefix(prefix, rib);
409 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700410
Ray Milkey269ffb92014-04-03 14:43:30 -0700411 if (update.getRibEntry().getNextHop().equals(
412 InetAddresses.forString("0.0.0.0"))) {
413 //Route originated by SDN domain
414 //We don't handle these at the moment
415 log.debug("Own route {} to {}", prefix,
416 update.getRibEntry().getNextHop().getHostAddress());
417 return;
418 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700419
Ray Milkey269ffb92014-04-03 14:43:30 -0700420 _processRibAdd(update);
421 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700422
Ray Milkey269ffb92014-04-03 14:43:30 -0700423 private void _processRibAdd(RibUpdate update) {
424 Prefix prefix = update.getPrefix();
425 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700426
Ray Milkey269ffb92014-04-03 14:43:30 -0700427 InetAddress dstIpAddress = rib.getNextHop();
428 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800429
Ray Milkey269ffb92014-04-03 14:43:30 -0700430 // See if we know the MAC address of the next hop
431 // TODO if we do not treat the next hop as a device in the future, we need to update this
432 // TODO: Fix the code below after deviceStorage was removed
433 /*
434 IDeviceObject nextHopDevice =
435 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700436
Ray Milkey269ffb92014-04-03 14:43:30 -0700437 if (nextHopDevice == null){
438 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
439 prefixesWaitingOnArp.put(dstIpAddress,
440 new RibUpdate(Operation.UPDATE, prefix, rib));
441 proxyArp.sendArpRequest(dstIpAddress, this, true);
442 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800443
Ray Milkey269ffb92014-04-03 14:43:30 -0700444 }
445 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
446 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700447
Ray Milkey269ffb92014-04-03 14:43:30 -0700448 // Find the attachment point (egress interface) of the next hop
449 Interface egressInterface = null;
450 if (bgpPeers.containsKey(dstIpAddress)) {
451 //Route to a peer
452 log.debug("Route to peer {}", dstIpAddress);
453 BgpPeer peer = bgpPeers.get(dstIpAddress);
454 egressInterface = interfaces.get(peer.getInterfaceName());
455 } else {
456 //Route to non-peer
457 log.debug("Route to non-peer {}", dstIpAddress);
458 egressInterface = interfacePtrie.match(
459 new Prefix(dstIpAddress.getAddress(), 32));
460 if (egressInterface == null) {
461 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
462 return;
463 }
464 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700465
Ray Milkey269ffb92014-04-03 14:43:30 -0700466 if (nextHopMacAddress == null) {
467 prefixesWaitingOnArp.put(dstIpAddress,
468 new RibUpdate(Operation.UPDATE, prefix, rib));
469 proxyArp.sendArpRequest(dstIpAddress, this, true);
470 return;
471 } else {
472 if (!bgpPeers.containsKey(dstIpAddress)) {
473 //If the prefix is for a non-peer we need to ensure there's a path,
474 //and push one if there isn't.
475 Path path = pushedPaths.get(dstIpAddress);
476 if (path == null) {
477 path = new Path(egressInterface, dstIpAddress);
478 calculateAndPushPath(path, nextHopMacAddress);
479 pushedPaths.put(dstIpAddress, path);
480 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700481
Ray Milkey269ffb92014-04-03 14:43:30 -0700482 path.incrementUsers();
483 prefixToPath.put(prefix, path);
484 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700485
Ray Milkey269ffb92014-04-03 14:43:30 -0700486 //For all prefixes we need to add the first-hop mac-rewriting flows
487 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
488 }
489 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700490
Ray Milkey269ffb92014-04-03 14:43:30 -0700491 /**
492 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
493 * to all other border switches
494 */
495 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
496 MACAddress nextHopMacAddress) {
497 log.debug("Adding flows for prefix {}, next hop mac {}",
498 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700499
Ray Milkey269ffb92014-04-03 14:43:30 -0700500 FlowPath flowPath = new FlowPath();
501 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700502
Ray Milkey269ffb92014-04-03 14:43:30 -0700503 // Set flowPath FlowPathType and FlowPathUserState
504 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
505 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800506
Ray Milkey269ffb92014-04-03 14:43:30 -0700507 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
508 // only to the first-host switches
509 FlowPathFlags flowPathFlags = new FlowPathFlags();
510 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
511 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800512
Ray Milkey269ffb92014-04-03 14:43:30 -0700513 // Create the DataPath object: dstSwitchPort
514 SwitchPort dstPort = new SwitchPort();
515 dstPort.setDpid(new Dpid(egressInterface.getDpid()));
516 dstPort.setPort(new Port(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800517
Ray Milkey269ffb92014-04-03 14:43:30 -0700518 // We only need one flow mod per switch, so pick one interface on each switch
519 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
520 for (Interface intf : interfaces.values()) {
521 if (!srcInterfaces.containsKey(intf.getDpid())
522 && !intf.equals(egressInterface)) {
523 srcInterfaces.put(intf.getDpid(), intf);
524 }
525 }
526 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800527
Ray Milkey269ffb92014-04-03 14:43:30 -0700528 if (egressInterface.equals(srcInterface)) {
529 continue;
530 }
pingping-linba5c52f2014-02-11 16:52:01 -0800531
Ray Milkey269ffb92014-04-03 14:43:30 -0700532 // Create flowPath FlowId
533 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800534
Ray Milkey269ffb92014-04-03 14:43:30 -0700535 // Create DataPath object: srcSwitchPort
536 SwitchPort srcPort = new SwitchPort();
537 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
538 srcPort.setPort(new Port(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800539
Ray Milkey269ffb92014-04-03 14:43:30 -0700540 DataPath dataPath = new DataPath();
541 dataPath.setSrcPort(srcPort);
542 dataPath.setDstPort(dstPort);
543 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800544
Ray Milkey269ffb92014-04-03 14:43:30 -0700545 // Create flow path matching condition(s): IPv4 Prefix
546 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
547 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
548 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
549 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
550 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300551
Ray Milkey269ffb92014-04-03 14:43:30 -0700552 /*
553 * Create the Flow Entry Action(s): dst-MAC rewrite action
554 */
555 FlowEntryActions flowEntryActions = new FlowEntryActions();
556 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
557 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
558 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
559 flowEntryActions.addAction(flowEntryAction1);
560 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800561
Ray Milkey269ffb92014-04-03 14:43:30 -0700562 // Flow Path installation, only to first hop switches
563 // TODO: Add the flow by using the new Path Intent framework
564 /*
565 if (flowManagerService.addFlow(flowPath) == null) {
566 log.error("Failed to install flow path to the first hop for " +
567 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
568 nextHopMacAddress);
569 }
570 else {
571 log.debug("Successfully installed flow path to the first hop " +
572 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
573 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800574
Ray Milkey269ffb92014-04-03 14:43:30 -0700575 pushedFlowIds.put(prefix, flowPath.flowId());
576 }
577 */
578 }
579 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700580
Ray Milkey269ffb92014-04-03 14:43:30 -0700581 public synchronized void processRibDelete(RibUpdate update) {
582 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700583
Ray Milkey269ffb92014-04-03 14:43:30 -0700584 if (ptree.remove(prefix, update.getRibEntry())) {
585 /*
586 * Only delete flows if an entry was actually removed from the trie.
587 * If no entry was removed, the <prefix, nexthop> wasn't there so
588 * it's probably already been removed and we don't need to do anything
589 */
590 _processDeletePrefix(prefix, update.getRibEntry());
591 }
592 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700593
Ray Milkey269ffb92014-04-03 14:43:30 -0700594 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
595 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700596
Ray Milkey269ffb92014-04-03 14:43:30 -0700597 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700598
Ray Milkey269ffb92014-04-03 14:43:30 -0700599 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
600 log.debug("Getting path for route with non-peer nexthop");
601 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700602
Ray Milkey269ffb92014-04-03 14:43:30 -0700603 if (path != null) {
604 //path could be null if we added to the Ptree but didn't push
605 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700606
Ray Milkey269ffb92014-04-03 14:43:30 -0700607 path.decrementUsers();
608 if (path.getUsers() <= 0 && !path.isPermanent()) {
609 deletePath(path);
610 pushedPaths.remove(path.getDstIpAddress());
611 }
612 }
613 }
614 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700615
Ray Milkey269ffb92014-04-03 14:43:30 -0700616 // TODO have not tested this module
617 private void deletePrefixFlows(Prefix prefix) {
618 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700619
Ray Milkey269ffb92014-04-03 14:43:30 -0700620 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
621 for (FlowId flowId : flowIds) {
622 // TODO: Delete the flow by using the new Path Intent framework
623 /*
624 if (log.isTraceEnabled()) {
625 //Trace the flow status by flowPath in the switch before deleting it
626 log.trace("Pushing a DELETE flow mod to flowPath : {}",
627 flowManagerService.getFlow(flowId).toString());
628 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700629
Ray Milkey269ffb92014-04-03 14:43:30 -0700630 if( flowManagerService.deleteFlow(flowId))
631 {
632 log.debug("Successfully deleted FlowId: {}",flowId);
633 }
634 else
635 {
636 log.debug("Failed to delete FlowId: {}",flowId);
637 }
638 */
639 }
640 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700641
Ray Milkey269ffb92014-04-03 14:43:30 -0700642 // TODO need to record the path and then delete here
643 private void deletePath(Path path) {
644 log.debug("Deleting flows for path to {}",
645 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700646
Ray Milkey269ffb92014-04-03 14:43:30 -0700647 // TODO need update
648 /*for (PushedFlowMod pfm : path.getFlowMods()) {
649 if (log.isTraceEnabled()) {
650 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
651 new Object[] {HexString.toHexString(pfm.getDpid()),
652 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
653 });
654 }
pingping-linba5c52f2014-02-11 16:52:01 -0800655
Ray Milkey269ffb92014-04-03 14:43:30 -0700656 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
657 }*/
658 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700659
660
Ray Milkey269ffb92014-04-03 14:43:30 -0700661 //TODO test next-hop changes
662 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800663
Ray Milkey269ffb92014-04-03 14:43:30 -0700664 /**
665 * On startup, we need to calculate a full mesh of paths between all gateway
666 * switches
667 */
668 private void setupFullMesh() {
669 //For each border router, calculate and install a path from every other
670 //border switch to said border router. However, don't install the entry
671 //in to the first hop switch, as we need to install an entry to rewrite
672 //for each prefix received. This will be done later when prefixes have
673 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700674
Ray Milkey269ffb92014-04-03 14:43:30 -0700675 for (BgpPeer peer : bgpPeers.values()) {
676 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700677
Ray Milkey269ffb92014-04-03 14:43:30 -0700678 //We know there's not already a Path here pushed, because this is
679 //called before all other routing
680 Path path = new Path(peerInterface, peer.getIpAddress());
681 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700682
Ray Milkey269ffb92014-04-03 14:43:30 -0700683 //See if we know the MAC address of the peer. If not we can't
684 //do anything until we learn it
685 // TODO: Fix the code below after deviceStorage was removed
686 MACAddress macAddress = null;
687 /*
688 IDeviceObject nextHopDevice =
689 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800690
Ray Milkey269ffb92014-04-03 14:43:30 -0700691 if(nextHopDevice == null){
692 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
693 //Put in the pending paths list first
694 pathsWaitingOnArp.put(peer.getIpAddress(), path);
695 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
696 continue;
697 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700698
Ray Milkey269ffb92014-04-03 14:43:30 -0700699 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
700 */
pingping-linba5c52f2014-02-11 16:52:01 -0800701
Ray Milkey269ffb92014-04-03 14:43:30 -0700702 if (macAddress == null) {
703 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
704 //Put in the pending paths list first
705 pathsWaitingOnArp.put(peer.getIpAddress(), path);
706 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
707 continue;
708 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700709
Ray Milkey269ffb92014-04-03 14:43:30 -0700710 //If we know the MAC, lets go ahead and push the paths to this peer
711 calculateAndPushPath(path, macAddress);
712 }
713 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700714
Ray Milkey269ffb92014-04-03 14:43:30 -0700715 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
716 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700717
Ray Milkey269ffb92014-04-03 14:43:30 -0700718 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
719 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800720
Ray Milkey269ffb92014-04-03 14:43:30 -0700721 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800722
Ray Milkey269ffb92014-04-03 14:43:30 -0700723 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800724
Ray Milkey269ffb92014-04-03 14:43:30 -0700725 // Set flowPath FlowPathType and FlowPathUserState
726 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
727 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800728
Ray Milkey269ffb92014-04-03 14:43:30 -0700729 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
730 FlowPathFlags flowPathFlags = new FlowPathFlags();
731 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
732 flowPath.setFlowPathFlags(flowPathFlags);
733
734 // Create the DataPath object: dstSwitchPort
735 SwitchPort dstPort = new SwitchPort();
736 dstPort.setDpid(new Dpid(dstInterface.getDpid()));
737 dstPort.setPort(new Port(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800738
Ray Milkey269ffb92014-04-03 14:43:30 -0700739 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800740
Ray Milkey269ffb92014-04-03 14:43:30 -0700741 if (dstInterface.equals(srcInterface)) {
742 continue;
743 }
pingping-linba5c52f2014-02-11 16:52:01 -0800744
Ray Milkey269ffb92014-04-03 14:43:30 -0700745 // Create flowPath FlowId
746 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800747
Ray Milkey269ffb92014-04-03 14:43:30 -0700748 // Create the DataPath object: srcSwitchPort
749 SwitchPort srcPort = new SwitchPort();
750 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
751 srcPort.setPort(new Port(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800752
Ray Milkey269ffb92014-04-03 14:43:30 -0700753 DataPath dataPath = new DataPath();
754 dataPath.setSrcPort(srcPort);
755 dataPath.setDstPort(dstPort);
756 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800757
Ray Milkey269ffb92014-04-03 14:43:30 -0700758 // Create the Flow Path Match condition(s)
759 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
760 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
761 flowEntryMatch.enableDstMac(dstMacAddress);
762 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800763
Ray Milkey269ffb92014-04-03 14:43:30 -0700764 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
765 // Shortest Path Flow, and is always the last action for the Flow Entries
766 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
767 // TODO: Add the flow by using the new Path Intent framework
768 /*
769 if (flowManagerService.addFlow(flowPath) == null) {
770 log.error("Failed to set up MAC based forwarding path to {}, {}",
771 path.getDstIpAddress().getHostAddress(),dstMacAddress);
772 }
773 else {
774 log.debug("Successfully set up MAC based forwarding path to {}, {}",
775 path.getDstIpAddress().getHostAddress(),dstMacAddress);
776 }
777 */
778 }
779 }
pingping-linba5c52f2014-02-11 16:52:01 -0800780
Ray Milkey269ffb92014-04-03 14:43:30 -0700781 /**
782 * Pre-actively install all BGP traffic paths from BGP host attachment point
783 * in SDN network to all the virtual gateways to BGP peers in other networks
784 */
785 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200786
Ray Milkey269ffb92014-04-03 14:43:30 -0700787 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800788
Ray Milkey269ffb92014-04-03 14:43:30 -0700789 FlowPath flowPath = new FlowPath();
790 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800791
Ray Milkey269ffb92014-04-03 14:43:30 -0700792 // Set flowPath FlowPathType and FlowPathUserState
793 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
794 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800795
Ray Milkey269ffb92014-04-03 14:43:30 -0700796 // Install flow paths between BGPd and its peers
797 // There is no need to set the FlowPathFlags
798 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800799
Ray Milkey269ffb92014-04-03 14:43:30 -0700800 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
pingping-linba5c52f2014-02-11 16:52:01 -0800801
Ray Milkey269ffb92014-04-03 14:43:30 -0700802 // Create the Flow Path Match condition(s)
803 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
804 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
pingping-linba5c52f2014-02-11 16:52:01 -0800805
Ray Milkey269ffb92014-04-03 14:43:30 -0700806 // Match both source address and dest address
807 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress() + "/32");
808 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800809
Ray Milkey269ffb92014-04-03 14:43:30 -0700810 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress().getHostAddress() + "/32");
811 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800812
Ray Milkey269ffb92014-04-03 14:43:30 -0700813 // Match TCP protocol
814 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800815
Ray Milkey269ffb92014-04-03 14:43:30 -0700816 // Match destination TCP port
817 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
818 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800819
Ray Milkey269ffb92014-04-03 14:43:30 -0700820 /**
821 * Create the DataPath: BGP -> BGP peer
822 */
823 // Flow path for src-TCP-port
824 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800825
Ray Milkey269ffb92014-04-03 14:43:30 -0700826 SwitchPort srcPort = new SwitchPort();
827 srcPort.setDpid(bgpdAttachmentPoint.dpid());
828 srcPort.setPort(bgpdAttachmentPoint.port());
829 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800830
Ray Milkey269ffb92014-04-03 14:43:30 -0700831 SwitchPort dstPort = new SwitchPort();
832 dstPort.setDpid(new Dpid(peerInterface.getDpid()));
833 dstPort.setPort(new Port(peerInterface.getSwitchPort().port()));
834 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800835
Ray Milkey269ffb92014-04-03 14:43:30 -0700836 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800837
Ray Milkey269ffb92014-04-03 14:43:30 -0700838 // TODO: Add the flow by using the new Path Intent framework
839 /*
840 if (flowManagerService.addFlow(flowPath) == null) {
841 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
842 bgpPeer.getIpAddress().getHostAddress());
843 }
844 else {
845 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
846 bgpPeer.getIpAddress().getHostAddress());
847 }
848 */
pingping-linba5c52f2014-02-11 16:52:01 -0800849
Ray Milkey269ffb92014-04-03 14:43:30 -0700850 // Disable dst-TCP-port, and set src-TCP-port
851 flowEntryMatch.disableDstTcpUdpPort();
852 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
853 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800854
Ray Milkey269ffb92014-04-03 14:43:30 -0700855 // Create a new FlowId
856 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800857
Ray Milkey269ffb92014-04-03 14:43:30 -0700858 // TODO: Add the flow by using the new Path Intent framework
859 /*
860 if (flowManagerService.addFlow(flowPath) == null) {
861 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
862 bgpPeer.getIpAddress().getHostAddress());
863 }
864 else {
865 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
866 bgpPeer.getIpAddress().getHostAddress());
867 }
868 */
pingping-linba5c52f2014-02-11 16:52:01 -0800869
Ray Milkey269ffb92014-04-03 14:43:30 -0700870 /**
871 * Create the DataPath: BGP <-BGP peer
872 */
873 // Reversed BGP flow path for src-TCP-port
874 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800875
Ray Milkey2476cac2014-04-08 11:03:21 -0700876 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800877
Ray Milkey2476cac2014-04-08 11:03:21 -0700878 SwitchPort reverseDstPort = new SwitchPort();
879 reverseDstPort.setDpid(bgpdAttachmentPoint.dpid());
880 reverseDstPort.setPort(bgpdAttachmentPoint.port());
881 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800882
Ray Milkey2476cac2014-04-08 11:03:21 -0700883 SwitchPort reverseSrcPort = new SwitchPort();
884 reverseSrcPort.setDpid(new Dpid(peerInterface.getDpid()));
885 reverseSrcPort.setPort(new Port(peerInterface.getSwitchPort().port()));
886 reverseDataPath.setSrcPort(reverseSrcPort);
887 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800888
Ray Milkey269ffb92014-04-03 14:43:30 -0700889 // reverse the dst IP and src IP addresses
890 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
891 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
892 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800893
Ray Milkey269ffb92014-04-03 14:43:30 -0700894 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800895
Ray Milkey269ffb92014-04-03 14:43:30 -0700896 // TODO: Add the flow by using the new Path Intent framework
897 /*
898 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800899
Ray Milkey269ffb92014-04-03 14:43:30 -0700900 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
901 bgpPeer.getIpAddress().getHostAddress());
902 }
903 else {
904 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
905 bgpPeer.getIpAddress().getHostAddress());
906 }
907 */
pingping-linba5c52f2014-02-11 16:52:01 -0800908
Ray Milkey269ffb92014-04-03 14:43:30 -0700909 // Reversed BGP flow path for dst-TCP-port
910 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800911
Ray Milkey269ffb92014-04-03 14:43:30 -0700912 // Disable src-TCP-port, and set the dst-TCP-port
913 flowEntryMatch.disableSrcTcpUdpPort();
914 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
915 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800916
Ray Milkey269ffb92014-04-03 14:43:30 -0700917 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800918
Ray Milkey269ffb92014-04-03 14:43:30 -0700919 // TODO: Add the flow by using the new Path Intent framework
920 /*
921 if (flowManagerService.addFlow(flowPath) == null) {
922 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
923 bgpPeer.getIpAddress().getHostAddress());
924 }
925 else {
926 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
927 bgpPeer.getIpAddress().getHostAddress());
928 }
929 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700930
Ray Milkey269ffb92014-04-03 14:43:30 -0700931 /**
932 * ICMP paths between BGPd and its peers
933 */
934 //match ICMP protocol BGP <- Peer
935 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800936
Ray Milkey269ffb92014-04-03 14:43:30 -0700937 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
938 flowEntryMatch.disableSrcTcpUdpPort();
939 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -0800940
Ray Milkey269ffb92014-04-03 14:43:30 -0700941 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800942
Ray Milkey2476cac2014-04-08 11:03:21 -0700943 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800944
Ray Milkey269ffb92014-04-03 14:43:30 -0700945 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800946
Ray Milkey269ffb92014-04-03 14:43:30 -0700947 // TODO: Add the flow by using the new Path Intent framework
948 /*
949 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800950
Ray Milkey269ffb92014-04-03 14:43:30 -0700951 log.error("Failed to set up ICMP path BGP <- Peer {}",
952 bgpPeer.getIpAddress().getHostAddress());
953 }
954 else {
955 log.debug("Successfully set up ICMP path BGP <- Peer {}",
956 bgpPeer.getIpAddress().getHostAddress());
957 }
958 */
pingping-linba5c52f2014-02-11 16:52:01 -0800959
Ray Milkey269ffb92014-04-03 14:43:30 -0700960 //match ICMP protocol BGP -> Peer
961 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800962
Ray Milkey269ffb92014-04-03 14:43:30 -0700963 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
964 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
965 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800966
Ray Milkey269ffb92014-04-03 14:43:30 -0700967 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800968
Ray Milkey269ffb92014-04-03 14:43:30 -0700969 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800970
Ray Milkey269ffb92014-04-03 14:43:30 -0700971 // TODO: Add the flow by using the new Path Intent framework
972 /*
973 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800974
Ray Milkey269ffb92014-04-03 14:43:30 -0700975 log.error("Failed to set up ICMP path BGP -> Peer {}",
976 bgpPeer.getIpAddress().getHostAddress());
977 }
978 else {
979 log.debug("Successfully set up ICMP path BGP -> Peer {}",
980 bgpPeer.getIpAddress().getHostAddress());
981 }
982 */
983 }
984 }
pingping-linba5c52f2014-02-11 16:52:01 -0800985
Ray Milkey269ffb92014-04-03 14:43:30 -0700986 @Override
987 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
988 log.debug("Received ARP response: {} => {}",
989 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700990
Ray Milkey269ffb92014-04-03 14:43:30 -0700991 /*
992 * We synchronize on this to prevent changes to the ptree while we're pushing
993 * flows to the switches. If the ptree changes, the ptree and switches
994 * could get out of sync.
995 */
996 synchronized (this) {
997 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700998
Ray Milkey269ffb92014-04-03 14:43:30 -0700999 if (path != null) {
1000 log.debug("Pushing path to {} at {} on {}", new Object[]{
1001 path.getDstIpAddress().getHostAddress(), macAddress,
1002 path.getDstInterface().getSwitchPort()});
1003 //These paths should always be to BGP peers. Paths to non-peers are
1004 //handled once the first prefix is ready to push
1005 if (pushedPaths.containsKey(path.getDstIpAddress())) {
1006 //A path already got pushed to this endpoint while we were waiting
1007 //for ARP. We'll copy over the permanent attribute if it is set on this path.
1008 if (path.isPermanent()) {
1009 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1010 }
1011 } else {
1012 calculateAndPushPath(path, macAddress);
1013 pushedPaths.put(path.getDstIpAddress(), path);
1014 }
1015 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001016
Ray Milkey269ffb92014-04-03 14:43:30 -07001017 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001018
Ray Milkey269ffb92014-04-03 14:43:30 -07001019 for (RibUpdate update : prefixesToPush) {
1020 //These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001021
Ray Milkey269ffb92014-04-03 14:43:30 -07001022 RibEntry rib = ptree.lookup(update.getPrefix());
1023 if (rib != null && rib.equals(update.getRibEntry())) {
1024 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1025 rib.getNextHop().getHostAddress());
1026 //We only push prefix flows if the prefix is still in the ptree
1027 //and the next hop is the same as our update. The prefix could
1028 //have been removed while we were waiting for the ARP, or the
1029 //next hop could have changed.
1030 _processRibAdd(update);
1031 } else {
1032 log.debug("Received ARP response, but {},{} is no longer in ptree",
1033 update.getPrefix(), update.getRibEntry());
1034 }
1035 }
1036 }
1037 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001038
Ray Milkey269ffb92014-04-03 14:43:30 -07001039 //TODO wait the priority module of the flow Manager
1040 private void setupArpFlows() {
1041 OFMatch match = new OFMatch();
1042 match.setDataLayerType(Ethernet.TYPE_ARP);
1043 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001044
Ray Milkey269ffb92014-04-03 14:43:30 -07001045 OFFlowMod fm = new OFFlowMod();
1046 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001047
Ray Milkey269ffb92014-04-03 14:43:30 -07001048 OFActionOutput action = new OFActionOutput();
1049 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1050 action.setMaxLength((short) 0xffff);
1051 List<OFAction> actions = new ArrayList<OFAction>(1);
1052 actions.add(action);
1053 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001054
Ray Milkey269ffb92014-04-03 14:43:30 -07001055 fm.setIdleTimeout((short) 0)
1056 .setHardTimeout((short) 0)
1057 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1058 .setCookie(0)
1059 .setCommand(OFFlowMod.OFPFC_ADD)
1060 .setPriority(ARP_PRIORITY)
1061 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001062
Ray Milkey269ffb92014-04-03 14:43:30 -07001063 for (String strdpid : switches) {
1064 flowCache.write(HexString.toLong(strdpid), fm);
1065 }
1066 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001067
Ray Milkey269ffb92014-04-03 14:43:30 -07001068 //TODO need update, waiting for the priority feature from flow Manager
1069 private void setupDefaultDropFlows() {
1070 OFFlowMod fm = new OFFlowMod();
1071 fm.setMatch(new OFMatch());
1072 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001073
Ray Milkey269ffb92014-04-03 14:43:30 -07001074 fm.setIdleTimeout((short) 0)
1075 .setHardTimeout((short) 0)
1076 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1077 .setCookie(0)
1078 .setCommand(OFFlowMod.OFPFC_ADD)
1079 .setPriority((short) 0)
1080 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001081
Ray Milkey269ffb92014-04-03 14:43:30 -07001082 OFFlowMod fmLLDP;
1083 OFFlowMod fmBDDP;
1084 try {
1085 fmLLDP = fm.clone();
1086 fmBDDP = fm.clone();
1087 } catch (CloneNotSupportedException e1) {
1088 log.error("Error cloning flow mod", e1);
1089 return;
1090 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001091
Ray Milkey269ffb92014-04-03 14:43:30 -07001092 OFMatch matchLLDP = new OFMatch();
1093 matchLLDP.setDataLayerType((short) 0x88cc);
1094 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1095 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001096
Ray Milkey269ffb92014-04-03 14:43:30 -07001097 OFMatch matchBDDP = new OFMatch();
1098 matchBDDP.setDataLayerType((short) 0x8942);
1099 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1100 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001101
Ray Milkey269ffb92014-04-03 14:43:30 -07001102 OFActionOutput action = new OFActionOutput();
1103 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1104 action.setMaxLength((short) 0xffff);
1105 List<OFAction> actions = new ArrayList<OFAction>(1);
1106 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001107
Ray Milkey269ffb92014-04-03 14:43:30 -07001108 fmLLDP.setActions(actions);
1109 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001110
Ray Milkey269ffb92014-04-03 14:43:30 -07001111 fmLLDP.setPriority(ARP_PRIORITY);
1112 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1113 fmBDDP.setPriority(ARP_PRIORITY);
1114 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001115
Ray Milkey269ffb92014-04-03 14:43:30 -07001116 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1117 flowModList.add(fm);
1118 flowModList.add(fmLLDP);
1119 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001120
Ray Milkey269ffb92014-04-03 14:43:30 -07001121 for (String strdpid : switches) {
1122 flowCache.write(HexString.toLong(strdpid), flowModList);
1123 }
1124 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001125
Ray Milkey269ffb92014-04-03 14:43:30 -07001126 private void beginRouting() {
1127 log.debug("Topology is now ready, beginning routing function");
1128 // TODO: Fix for the new Topology Network Graph
1129 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001130
Ray Milkey269ffb92014-04-03 14:43:30 -07001131 // Wait Pavlin's API. We need the following functions.
1132 /*setupArpFlows();
1133 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001134
Ray Milkey269ffb92014-04-03 14:43:30 -07001135 setupBgpPaths();
1136 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001137
Ray Milkey269ffb92014-04-03 14:43:30 -07001138 //Suppress link discovery on external-facing router ports
1139 for (Interface intf : interfaces.values()) {
1140 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1141 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001142
Ray Milkey269ffb92014-04-03 14:43:30 -07001143 bgpUpdatesExecutor.execute(new Runnable() {
1144 @Override
1145 public void run() {
1146 doUpdatesThread();
1147 }
1148 });
1149 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001150
Ray Milkey269ffb92014-04-03 14:43:30 -07001151 // Before inserting the paths for BGP traffic, we should check
1152 // whether all the switches in the configure file are discovered by onos.
1153 private void checkSwitchesConnected() {
1154 for (String dpid : switches) {
1155 // TODO: Fix the code below after topoSwitchSerice was removed
1156 /*
1157 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1158 getActiveSwitches().iterator();
1159 while(activeSwitches.hasNext())
1160 {
1161 ISwitchObject switchObject = activeSwitches.next();
1162 if (switchObject.getDPID().equals(dpid)) {
1163 break;
1164 }
1165 if(activeSwitches.hasNext() == false) {
1166 log.debug("Not all switches are here yet");
1167 return;
1168 }
1169 }
1170 */
1171 }
1172 switchesConnected = true;
1173 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001174
Ray Milkey269ffb92014-04-03 14:43:30 -07001175 //Actually we only need to go half way round to verify full mesh connectivity
1176 //(n^2)/2
1177 private void checkTopologyReady() {
1178 for (Interface dstInterface : interfaces.values()) {
1179 for (Interface srcInterface : interfaces.values()) {
1180 if (dstInterface.equals(srcInterface)) {
1181 continue;
1182 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001183
Ray Milkey269ffb92014-04-03 14:43:30 -07001184 // TODO: Fix for the new Topology Network Graph
1185 /*
1186 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1187 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001188
Ray Milkey269ffb92014-04-03 14:43:30 -07001189 if (shortestPath == null){
1190 log.debug("Shortest path between {} and {} not found",
1191 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1192 return;
1193 }
1194 */
1195 }
1196 }
1197 topologyReady = true;
1198 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001199
Ray Milkey269ffb92014-04-03 14:43:30 -07001200 private void checkStatus() {
1201 if (!switchesConnected) {
1202 checkSwitchesConnected();
1203 }
1204 boolean oldTopologyReadyStatus = topologyReady;
1205 if (switchesConnected && !topologyReady) {
1206 checkTopologyReady();
1207 }
1208 if (!oldTopologyReadyStatus && topologyReady) {
1209 beginRouting();
1210 }
1211 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001212
Ray Milkey269ffb92014-04-03 14:43:30 -07001213 private void doUpdatesThread() {
1214 boolean interrupted = false;
1215 try {
1216 while (true) {
1217 try {
1218 RibUpdate update = ribUpdates.take();
1219 switch (update.getOperation()) {
1220 case UPDATE:
1221 if (validateUpdate(update)) {
1222 processRibAdd(update);
1223 } else {
1224 log.debug("Rib UPDATE out of order: {} via {}",
1225 update.getPrefix(), update.getRibEntry().getNextHop());
1226 }
1227 break;
1228 case DELETE:
1229 if (validateUpdate(update)) {
1230 processRibDelete(update);
1231 } else {
1232 log.debug("Rib DELETE out of order: {} via {}",
1233 update.getPrefix(), update.getRibEntry().getNextHop());
1234 }
1235 break;
1236 }
1237 } catch (InterruptedException e) {
1238 log.debug("Interrupted while taking from updates queue", e);
1239 interrupted = true;
1240 } catch (Exception e) {
1241 log.debug("exception", e);
1242 }
1243 }
1244 } finally {
1245 if (interrupted) {
1246 Thread.currentThread().interrupt();
1247 }
1248 }
1249 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001250
Ray Milkey269ffb92014-04-03 14:43:30 -07001251 private boolean validateUpdate(RibUpdate update) {
1252 RibEntry newEntry = update.getRibEntry();
1253 RibEntry oldEntry = ptree.lookup(update.getPrefix());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001254
Ray Milkey269ffb92014-04-03 14:43:30 -07001255 //If there is no existing entry we must assume this is the most recent
1256 //update. However this might not always be the case as we might have a
1257 //POST then DELETE reordering.
1258 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1259 if (oldEntry == null) {
1260 return true;
1261 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001262
Ray Milkey269ffb92014-04-03 14:43:30 -07001263 // This handles the case where routes are gathered in the initial
1264 // request because they don't have sequence number info
1265 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1266 return true;
1267 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001268
Ray Milkey269ffb92014-04-03 14:43:30 -07001269 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1270 return true;
1271 } else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1272 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1273 return true;
1274 } else {
1275 return false;
1276 }
1277 } else {
1278 return false;
1279 }
1280 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001281
Ray Milkey269ffb92014-04-03 14:43:30 -07001282 // The code below should be reimplemented after removal of Floodlight's
1283 // ITopologyService API. It should be implemented on top of network graph
1284 // notifications. (It was pretty hacky anyway...)
1285 /*
1286 @Override
1287 public void topologyChanged() {
1288 if (topologyReady) {
1289 return;
1290 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001291
Ray Milkey269ffb92014-04-03 14:43:30 -07001292 boolean refreshNeeded = false;
1293 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1294 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1295 //We don't need to recalculate anything for just link updates
1296 //They happen very frequently
1297 refreshNeeded = true;
1298 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001299
Ray Milkey269ffb92014-04-03 14:43:30 -07001300 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001301
Ray Milkey269ffb92014-04-03 14:43:30 -07001302 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1303 synchronized (linkUpdates) {
1304 linkUpdates.add(ldu);
1305 }
1306 }
1307 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001308
Ray Milkey269ffb92014-04-03 14:43:30 -07001309 if (refreshNeeded && !topologyReady){
1310 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1311 }
1312 }
1313 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001314
Ray Milkey269ffb92014-04-03 14:43:30 -07001315 @Override
1316 public void addedSwitch(IOFSwitch sw) {
1317 if (!topologyReady) {
1318 sw.clearAllFlowMods();
1319 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001320
Ray Milkey269ffb92014-04-03 14:43:30 -07001321 flowCache.switchConnected(sw);
1322 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001323
Ray Milkey269ffb92014-04-03 14:43:30 -07001324 @Override
1325 public void removedSwitch(IOFSwitch sw) {
1326 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001327
Ray Milkey269ffb92014-04-03 14:43:30 -07001328 @Override
1329 public void switchPortChanged(Long switchId) {
1330 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001331
Ray Milkey269ffb92014-04-03 14:43:30 -07001332 @Override
1333 public String getName() {
1334 return "BgpRoute";
1335 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001336
Ray Milkey269ffb92014-04-03 14:43:30 -07001337 /*
1338 * IConfigInfoService methods
1339 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001340
Ray Milkey269ffb92014-04-03 14:43:30 -07001341 @Override
1342 public boolean isInterfaceAddress(InetAddress address) {
1343 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1344 return (intf != null && intf.getIpAddress().equals(address));
1345 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001346
Ray Milkey269ffb92014-04-03 14:43:30 -07001347 @Override
1348 public boolean inConnectedNetwork(InetAddress address) {
1349 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1350 return (intf != null && !intf.getIpAddress().equals(address));
1351 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001352
Ray Milkey269ffb92014-04-03 14:43:30 -07001353 @Override
1354 public boolean fromExternalNetwork(long inDpid, short inPort) {
1355 for (Interface intf : interfaces.values()) {
1356 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1357 return true;
1358 }
1359 }
1360 return false;
1361 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001362
Ray Milkey269ffb92014-04-03 14:43:30 -07001363 @Override
1364 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1365 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1366 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001367
Ray Milkey269ffb92014-04-03 14:43:30 -07001368 @Override
1369 public boolean hasLayer3Configuration() {
1370 return !interfaces.isEmpty();
1371 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001372
Ray Milkey269ffb92014-04-03 14:43:30 -07001373 @Override
1374 public MACAddress getRouterMacAddress() {
1375 return bgpdMacAddress;
1376 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001377
Ray Milkey269ffb92014-04-03 14:43:30 -07001378 @Override
1379 public short getVlan() {
1380 return vlan;
1381 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001382}