blob: ed7a8ee52c49aa1fc48925551b4fa155d5ba0710 [file] [log] [blame]
Jonathan Hart8f6dc092014-04-18 15:56:43 -07001package net.onrc.onos.apps.sdnip;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
Jonathan Hartd1f23252013-06-13 15:17:05 +12003import java.io.File;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07004import java.io.IOException;
5import java.net.InetAddress;
pingping-lina2cbfad2013-03-07 08:39:21 +08006import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07007import java.util.Collection;
pingping-lin0426dee2014-08-27 15:03:17 -07008import java.util.Collections;
pingping-lina2cbfad2013-03-07 08:39:21 +08009import java.util.HashMap;
pingping-lin1ada7ce2014-08-14 13:45:22 -070010import java.util.HashSet;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070011import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070012import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070013import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120014import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120015import java.util.concurrent.BlockingQueue;
pingping-lin1ada7ce2014-08-14 13:45:22 -070016import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120017import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120018import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120019import java.util.concurrent.LinkedBlockingQueue;
pingping-lina2cbfad2013-03-07 08:39:21 +080020
21import net.floodlightcontroller.core.module.FloodlightModuleContext;
22import net.floodlightcontroller.core.module.FloodlightModuleException;
23import net.floodlightcontroller.core.module.IFloodlightModule;
24import net.floodlightcontroller.core.module.IFloodlightService;
pingping-lina2cbfad2013-03-07 08:39:21 +080025import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120026import net.floodlightcontroller.util.MACAddress;
pingping-lin1ada7ce2014-08-14 13:45:22 -070027import net.onrc.onos.api.newintent.IntentService;
28import net.onrc.onos.api.newintent.MultiPointToSinglePointIntent;
Jonathan Hart0961fe82014-04-03 09:56:25 -070029import net.onrc.onos.apps.proxyarp.IArpRequester;
30import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart8f6dc092014-04-18 15:56:43 -070031import net.onrc.onos.apps.sdnip.RibUpdate.Operation;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070032import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutable;
Komal Shah399a2922014-05-28 01:57:40 -070033import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutableNew;
34import net.onrc.onos.core.intent.IntentOperation;
35import net.onrc.onos.core.intent.IntentOperationList;
36import net.onrc.onos.core.intent.ShortestPathIntent;
37import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
Jonathan Harta99ec672014-04-03 11:30:34 -070038import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070039import net.onrc.onos.core.main.config.IConfigInfoService;
pingping-lin1ada7ce2014-08-14 13:45:22 -070040import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
41import net.onrc.onos.core.matchaction.match.PacketMatch;
42import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
43import net.onrc.onos.core.newintent.IdBlockAllocatorBasedIntentIdGenerator;
Komal Shah399a2922014-05-28 01:57:40 -070044import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart23701d12014-04-03 10:45:48 -070045import net.onrc.onos.core.util.Dpid;
pingping-lin1ada7ce2014-08-14 13:45:22 -070046import net.onrc.onos.core.util.IPv4;
Yuta HIGUCHIfb564502014-06-16 21:29:00 -070047import net.onrc.onos.core.util.PortNumber;
Jonathan Hart23701d12014-04-03 10:45:48 -070048import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080049import net.sf.json.JSONArray;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070050import net.sf.json.JSONException;
pingping-line2a09ca2013-03-23 09:33:58 +080051import net.sf.json.JSONObject;
52import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080053
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070054import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120055import org.codehaus.jackson.JsonParseException;
56import org.codehaus.jackson.map.JsonMappingException;
57import org.codehaus.jackson.map.ObjectMapper;
pingping-lina2cbfad2013-03-07 08:39:21 +080058import org.slf4j.Logger;
59import org.slf4j.LoggerFactory;
60
Jonathan Hart4dfc3652013-08-02 20:22:36 +120061import com.google.common.collect.HashMultimap;
62import com.google.common.collect.Multimaps;
63import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120064import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120065import com.google.common.util.concurrent.ThreadFactoryBuilder;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070066import com.googlecode.concurrenttrees.radix.RadixTree;
67import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
68import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
69import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120070
pingping-lin1ada7ce2014-08-14 13:45:22 -070071/**
72 * This class sets up BGP paths, handles RIB updates and relative intents.
73 * TODO: Thread-safe.
74 */
Jonathan Hart8f6dc092014-04-18 15:56:43 -070075public class SdnIp implements IFloodlightModule, ISdnIpService,
pingping-lin1ada7ce2014-08-14 13:45:22 -070076 IArpRequester, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070077
Jonathan Hart8f6dc092014-04-18 15:56:43 -070078 private static final Logger log = LoggerFactory.getLogger(SdnIp.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080079
Ray Milkey269ffb92014-04-03 14:43:30 -070080 private ILinkDiscoveryService linkDiscoveryService;
81 private IRestApiService restApi;
82 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070083
Jonathan Hartf6978ce2014-06-23 11:20:04 -070084 private InvertedRadixTree<RibEntry> bgpRoutes;
85 private InvertedRadixTree<Interface> interfaceRoutes;
86
Ray Milkey269ffb92014-04-03 14:43:30 -070087 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070088
Ray Milkey269ffb92014-04-03 14:43:30 -070089 private String bgpdRestIp;
90 private String routerId;
Ray Milkey5df613b2014-04-15 10:50:56 -070091 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
92 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070093
Komal Shah399a2922014-05-28 01:57:40 -070094 /* ShortestPath Intent Variables */
Sho SHIMIZU9ec39822014-07-10 17:15:12 -070095 private final String caller = "SdnIp";
Komal Shah399a2922014-05-28 01:57:40 -070096 private IControllerRegistryService controllerRegistryService;
pingping-lin1ada7ce2014-08-14 13:45:22 -070097 private IntentService intentService;
Komal Shah399a2922014-05-28 01:57:40 -070098 private IPathCalcRuntimeService pathRuntime;
99 /* Shortest Intent Path Variables */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700100 private IdBlockAllocatorBasedIntentIdGenerator intentIdGenerator;
101 //private static final short ARP_PRIORITY = 20;
Komal Shah399a2922014-05-28 01:57:40 -0700102
pingping-lin1ada7ce2014-08-14 13:45:22 -0700103 //private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700104
Jonathan Hart938a0152014-04-07 18:27:31 -0700105 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700106 private List<String> switches;
107 private Map<String, Interface> interfaces;
108 private Map<InetAddress, BgpPeer> bgpPeers;
109 private SwitchPort bgpdAttachmentPoint;
110 private MACAddress bgpdMacAddress;
111 private short vlan;
pingping-lin0426dee2014-08-27 15:03:17 -0700112 private Set<SwitchPort> externalNetworkSwitchPorts;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700113
Ray Milkey269ffb92014-04-03 14:43:30 -0700114 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700115
Ray Milkey269ffb92014-04-03 14:43:30 -0700116 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700117
pingping-lin1ada7ce2014-08-14 13:45:22 -0700118 private ConcurrentHashMap<Prefix, MultiPointToSinglePointIntent> pushedRouteIntents;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700119
pingping-lin1ada7ce2014-08-14 13:45:22 -0700120 /**
121 * SDN-IP application has a configuration file. This method is to read all
122 * the info from this file.
123 *
124 * @param configFilename the name of configuration file for SDN-IP application
125 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700126 private void readConfiguration(String configFilename) {
127 File gatewaysFile = new File(configFilename);
128 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700129
Ray Milkey269ffb92014-04-03 14:43:30 -0700130 try {
131 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700132
Ray Milkey269ffb92014-04-03 14:43:30 -0700133 switches = config.getSwitches();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700134 interfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700135 for (Interface intf : config.getInterfaces()) {
136 interfaces.put(intf.getName(), intf);
pingping-lin0426dee2014-08-27 15:03:17 -0700137 externalNetworkSwitchPorts.add(new SwitchPort(intf.getDpid(),
138 intf.getPort()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700139 }
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700140 bgpPeers = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 for (BgpPeer peer : config.getPeers()) {
142 bgpPeers.put(peer.getIpAddress(), peer);
143 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700144
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 bgpdAttachmentPoint = new SwitchPort(
146 new Dpid(config.getBgpdAttachmentDpid()),
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700147 PortNumber.uint16(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700148
Ray Milkey269ffb92014-04-03 14:43:30 -0700149 bgpdMacAddress = config.getBgpdMacAddress();
150 vlan = config.getVlan();
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -0700151 } catch (JsonParseException | JsonMappingException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700152 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700153 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700154 } catch (IOException e) {
155 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700156 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700157 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700158
pingping-lin1ada7ce2014-08-14 13:45:22 -0700159 // Populate the interface InvertedRadixTree
Ray Milkey269ffb92014-04-03 14:43:30 -0700160 for (Interface intf : interfaces.values()) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700161 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
162 intf.getPrefixLength());
163 interfaceRoutes.put(prefix.toBinaryString(), intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700164 }
165 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700166
Ray Milkey269ffb92014-04-03 14:43:30 -0700167 @Override
168 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700169 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700170 l.add(ISdnIpService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700171 l.add(IConfigInfoService.class);
172 return l;
173 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700174
Ray Milkey269ffb92014-04-03 14:43:30 -0700175 @Override
176 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700177 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700178 m.put(ISdnIpService.class, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700179 m.put(IConfigInfoService.class, this);
180 return m;
181 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800182
Ray Milkey269ffb92014-04-03 14:43:30 -0700183 @Override
184 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700185 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700186 l.add(IRestApiService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700187 l.add(IControllerRegistryService.class);
188 l.add(IPathCalcRuntimeService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700189 return l;
190 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700191
Ray Milkey269ffb92014-04-03 14:43:30 -0700192 @Override
193 public void init(FloodlightModuleContext context)
194 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700195
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700196 bgpRoutes = new ConcurrentInvertedRadixTree<>(
197 new DefaultByteArrayNodeFactory());
198 interfaceRoutes = new ConcurrentInvertedRadixTree<>(
199 new DefaultByteArrayNodeFactory());
pingping-lin0426dee2014-08-27 15:03:17 -0700200 externalNetworkSwitchPorts = new HashSet<SwitchPort>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700201
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700202 ribUpdates = new LinkedBlockingQueue<>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700203
pingping-lin1ada7ce2014-08-14 13:45:22 -0700204 // Register REST handler.
Ray Milkey269ffb92014-04-03 14:43:30 -0700205 restApi = context.getServiceImpl(IRestApiService.class);
206 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800207
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700208 controllerRegistryService = context
209 .getServiceImpl(IControllerRegistryService.class);
pingping-linbec31fc2014-08-28 11:48:41 -0700210 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
211 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700212
pingping-lin1ada7ce2014-08-14 13:45:22 -0700213 intentIdGenerator = new IdBlockAllocatorBasedIntentIdGenerator(
214 controllerRegistryService);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700215
pingping-lin1ada7ce2014-08-14 13:45:22 -0700216 // TODO: initialize intentService
217
218 pushedRouteIntents = new ConcurrentHashMap<>();
219
Ray Milkey269ffb92014-04-03 14:43:30 -0700220 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
221 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700222
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700223 //flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700224
Ray Milkey269ffb92014-04-03 14:43:30 -0700225 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
226 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700227
Jonathan Hart938a0152014-04-07 18:27:31 -0700228 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700229 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
230 if (bgpdRestIp == null) {
231 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700232 throw new ConfigurationRuntimeException(
233 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700234 } else {
235 log.info("BgpdRestIp set to {}", bgpdRestIp);
236 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700237
Ray Milkey269ffb92014-04-03 14:43:30 -0700238 routerId = context.getConfigParams(this).get("RouterId");
239 if (routerId == null) {
240 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700241 throw new ConfigurationRuntimeException(
242 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700243 } else {
244 log.info("RouterId set to {}", routerId);
245 }
pingping-linba5c52f2014-02-11 16:52:01 -0800246
Ray Milkey269ffb92014-04-03 14:43:30 -0700247 String configFilenameParameter = context.getConfigParams(this).get("configfile");
248 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700249 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700250 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700251 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700252
Ray Milkey5df613b2014-04-15 10:50:56 -0700253 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700254 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700255
Ray Milkey269ffb92014-04-03 14:43:30 -0700256 @Override
257 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700258 restApi.addRestletRoutable(new SdnIpWebRoutable());
Komal Shah399a2922014-05-28 01:57:40 -0700259 restApi.addRestletRoutable(new SdnIpWebRoutableNew());
pingping-linba5c52f2014-02-11 16:52:01 -0800260
Jonathan Hart938a0152014-04-07 18:27:31 -0700261 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700262 retrieveRib();
263 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800264
Ray Milkey269ffb92014-04-03 14:43:30 -0700265 @Override
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700266 public RadixTree<RibEntry> getPtree() {
267 return bgpRoutes;
Ray Milkey269ffb92014-04-03 14:43:30 -0700268 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700269
Ray Milkey269ffb92014-04-03 14:43:30 -0700270 @Override
271 public void clearPtree() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700272 log.warn("Clear table operation not supported");
Ray Milkey269ffb92014-04-03 14:43:30 -0700273 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700274
Ray Milkey269ffb92014-04-03 14:43:30 -0700275 @Override
Jonathan Hart31e15f12014-04-10 10:33:00 -0700276 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700277 return bgpdRestIp;
278 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700279
Ray Milkey269ffb92014-04-03 14:43:30 -0700280 @Override
281 public String getRouterId() {
282 return routerId;
283 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700284
pingping-lin1ada7ce2014-08-14 13:45:22 -0700285 /**
286 * SDN-IP application will fetch all rib entries from BGPd when it starts.
287 * Especially when we restart SDN-IP application while the BGPd has been
288 * running all the time. Then before SDN-IP application re-connects to BGPd,
289 * there are already lots of rib entries in BGPd.
290 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700291 private void retrieveRib() {
292 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
293 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700294
Jonathan Hart938a0152014-04-07 18:27:31 -0700295 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700296 return;
297 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700298
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700299 try {
300 response = response.replaceAll("\"", "'");
301 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
302 JSONArray ribArray = jsonObj.getJSONArray("rib");
303 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700304
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700305 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700306
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700307 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700308
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700309 for (int j = 0; j < size; j++) {
310 JSONObject ribEntry = ribArray.getJSONObject(j);
311 String prefix = ribEntry.getString("prefix");
312 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700313
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700314 // Insert each rib entry into the local rib
315 String[] substring = prefix.split("/");
316 String prefix1 = substring[0];
317 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700318
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700319 Prefix p;
320 try {
321 p = new Prefix(prefix1, Integer.parseInt(mask1));
322 } catch (NumberFormatException e) {
323 log.warn("Wrong mask format in RIB JSON: {}", mask1);
324 continue;
325 } catch (IllegalArgumentException e1) {
326 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
327 continue;
328 }
329
330 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
331
332 try {
333 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
334 } catch (InterruptedException e) {
335 log.debug("Interrupted while pushing onto update queue");
336 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700337 }
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700338 } catch (JSONException e) {
339 // TODO don't parse JSON manually
340 log.error("Error parsing inital route table JSON:", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700341 }
342 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700343
pingping-lin1ada7ce2014-08-14 13:45:22 -0700344 /**
345 * Put RIB update to RIB update queue.
346 *
347 * @param update RIB update
348 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700349 @Override
350 public void newRibUpdate(RibUpdate update) {
351 try {
352 ribUpdates.put(update);
353 } catch (InterruptedException e) {
354 log.debug("Interrupted while putting on ribUpdates queue", e);
355 Thread.currentThread().interrupt();
356 }
357 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700358
pingping-lin1ada7ce2014-08-14 13:45:22 -0700359 /**
360 * Process adding RIB update.
361 * Put new RIB update into InvertedRadixTree. If there was an existing nexthop
362 * for this prefix, but the next hop was different, then execute deleting old
363 * RIB update. If the next hop is the SDN domain, we do not handle it at the
364 * moment. Otherwise, execute adding RIB.
365 *
366 * @param update RIB update
367 */
Jonathan Hart43f28742014-08-22 16:34:05 -0700368 protected void processRibAdd(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700369 synchronized (this) {
370 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700371
Jonathan Hart938a0152014-04-07 18:27:31 -0700372 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700373
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700374 RibEntry rib = bgpRoutes.put(prefix.toBinaryString(), update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700375
Jonathan Hart938a0152014-04-07 18:27:31 -0700376 if (rib != null && !rib.equals(update.getRibEntry())) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700377 // There was an existing nexthop for this prefix. This update
pingping-lin1ada7ce2014-08-14 13:45:22 -0700378 // supersedes that, so we need to remove the old flows for this
379 // prefix from the switches
380 executeDeleteRoute(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700381 }
Ray Milkey5d406012014-04-08 14:44:41 -0700382
Jonathan Hart938a0152014-04-07 18:27:31 -0700383 if (update.getRibEntry().getNextHop().equals(
384 InetAddresses.forString("0.0.0.0"))) {
385 // Route originated by SDN domain
386 // We don't handle these at the moment
387 log.debug("Own route {} to {}", prefix,
388 update.getRibEntry().getNextHop().getHostAddress());
389 return;
390 }
Ray Milkey5d406012014-04-08 14:44:41 -0700391
Ray Milkey7531a342014-04-11 15:08:12 -0700392 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700393 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700394 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700395
pingping-lin1ada7ce2014-08-14 13:45:22 -0700396 /**
397 * Execute adding RIB update.
398 * Find out the egress Interface and MAC address of next hop router for this
399 * RIB update. If the MAC address can not be found in ARP cache, then this
400 * prefix will be put in prefixesWaitingOnArp queue. Otherwise, new flow
401 * intent will be created and installed.
402 *
403 * @param update RIB update
404 */
Ray Milkey7531a342014-04-11 15:08:12 -0700405 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700406
Ray Milkey269ffb92014-04-03 14:43:30 -0700407 Prefix prefix = update.getPrefix();
408 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700409
pingping-lin1ada7ce2014-08-14 13:45:22 -0700410 InetAddress nextHopIpAddress = rib.getNextHop();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700411
Jonathan Hart43f28742014-08-22 16:34:05 -0700412 // See if we know the MAC address of the next hop
413 MACAddress nextHopMacAddress = proxyArp.getMacAddress(nextHopIpAddress);
pingping-lin1ada7ce2014-08-14 13:45:22 -0700414
Jonathan Hart43f28742014-08-22 16:34:05 -0700415 if (nextHopMacAddress == null) {
416 prefixesWaitingOnArp.put(nextHopIpAddress,
417 new RibUpdate(Operation.UPDATE, prefix, rib));
418 proxyArp.sendArpRequest(nextHopIpAddress, this, true);
419 return;
420 }
421
422 addRouteIntentToNextHop(prefix, nextHopIpAddress, nextHopMacAddress);
423 }
424
425 /**
426 * Adds a route intent given a prefix and a next hop IP address. This
427 * method will find the egress interface for the intent.
428 *
429 * @param prefix IP prefix of the route to add
430 * @param nextHopIpAddress IP address of the next hop
431 * @param nextHopMacAddress MAC address of the next hop
432 */
433 private void addRouteIntentToNextHop(Prefix prefix, InetAddress nextHopIpAddress,
434 MACAddress nextHopMacAddress) {
435
436 // Find the attachment point (egress interface) of the next hop
437 Interface egressInterface;
pingping-lin1ada7ce2014-08-14 13:45:22 -0700438 if (bgpPeers.containsKey(nextHopIpAddress)) {
439 // Route to a peer
440 log.debug("Route to peer {}", nextHopIpAddress);
441 BgpPeer peer = bgpPeers.get(nextHopIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700442 egressInterface = interfaces.get(peer.getInterfaceName());
443 } else {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700444 // Route to non-peer
445 log.debug("Route to non-peer {}", nextHopIpAddress);
446 egressInterface = getOutgoingInterface(nextHopIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700447 if (egressInterface == null) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700448 log.warn("No outgoing interface found for {}", nextHopIpAddress
449 .getHostAddress());
Ray Milkey269ffb92014-04-03 14:43:30 -0700450 return;
451 }
452 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700453
Jonathan Hart43f28742014-08-22 16:34:05 -0700454 doAddRouteIntent(prefix, egressInterface, nextHopMacAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700455 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700456
Ray Milkey269ffb92014-04-03 14:43:30 -0700457 /**
pingping-lin1ada7ce2014-08-14 13:45:22 -0700458 * Install a flow intent for a prefix.
459 * Intent will match dst IP prefix and rewrite dst MAC address at all other
460 * border switches, then forward packets according to dst MAC address.
461 *
462 * @param prefix IP prefix from BGP route
463 * @param egressInterface egress Interface connected to next hop router
464 * @param nextHopMacAddress MAC address of next hop router
Ray Milkey269ffb92014-04-03 14:43:30 -0700465 */
Jonathan Hart43f28742014-08-22 16:34:05 -0700466 private void doAddRouteIntent(Prefix prefix, Interface egressInterface,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700467 MACAddress nextHopMacAddress) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700468 log.debug("Adding intent for prefix {}, next hop mac {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700469 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700470
pingping-lin1ada7ce2014-08-14 13:45:22 -0700471 MultiPointToSinglePointIntent pushedIntent = pushedRouteIntents.get(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700472
pingping-lin1ada7ce2014-08-14 13:45:22 -0700473 // Just for testing.
474 if (pushedIntent != null) {
475 log.error("There should not be a pushed intent: {}", pushedIntent);
476 }
pingping-linba5c52f2014-02-11 16:52:01 -0800477
pingping-lin1ada7ce2014-08-14 13:45:22 -0700478 SwitchPort egressPort = egressInterface.getSwitchPort();
pingping-linba5c52f2014-02-11 16:52:01 -0800479
pingping-lin1ada7ce2014-08-14 13:45:22 -0700480 Set<SwitchPort> ingressPorts = new HashSet<SwitchPort>();
pingping-linba5c52f2014-02-11 16:52:01 -0800481
Ray Milkey269ffb92014-04-03 14:43:30 -0700482 for (Interface intf : interfaces.values()) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700483 if (!intf.equals(egressInterface)) {
484 SwitchPort srcPort = intf.getSwitchPort();
485 ingressPorts.add(srcPort);
Ray Milkey269ffb92014-04-03 14:43:30 -0700486 }
487 }
pingping-linba5c52f2014-02-11 16:52:01 -0800488
pingping-lin1ada7ce2014-08-14 13:45:22 -0700489 // Match the destination IP prefix at the first hop
490 PacketMatchBuilder builder = new PacketMatchBuilder();
491 builder.setDstIp(new IPv4(InetAddresses
492 .coerceToInteger(prefix.getInetAddress())),
493 (short) prefix.getPrefixLength());
494 PacketMatch packetMatch = builder.build();
pingping-linba5c52f2014-02-11 16:52:01 -0800495
pingping-lin1ada7ce2014-08-14 13:45:22 -0700496 // Rewrite the destination MAC address
497 ModifyDstMacAction modifyDstMacAction =
498 new ModifyDstMacAction(nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800499
pingping-lin1ada7ce2014-08-14 13:45:22 -0700500 MultiPointToSinglePointIntent intent =
501 new MultiPointToSinglePointIntent(intentIdGenerator.getNewId(),
502 packetMatch, modifyDstMacAction, ingressPorts, egressPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800503
pingping-lin1ada7ce2014-08-14 13:45:22 -0700504 intentService.submit(intent);
pingping-linba5c52f2014-02-11 16:52:01 -0800505
pingping-lin1ada7ce2014-08-14 13:45:22 -0700506 // Maintain the Intent
507 pushedRouteIntents.put(prefix, intent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700508 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700509
pingping-lin1ada7ce2014-08-14 13:45:22 -0700510 /**
511 * Remove prefix from InvertedRadixTree, if success, then try to delete the
512 * relative intent.
513 *
514 * @param update RIB update
515 */
Sho SHIMIZUba372192014-07-10 08:59:57 -0700516 private void processRibDelete(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700517 synchronized (this) {
518 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700519
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700520 // if (ptree.remove(prefix, update.getRibEntry())) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700521
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700522 // TODO check the change of logic here - remove doesn't check that
pingping-lin1ada7ce2014-08-14 13:45:22 -0700523 // the rib entry was what we expected (and we can't do this
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700524 // concurrently)
pingping-lin1ada7ce2014-08-14 13:45:22 -0700525
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700526 if (bgpRoutes.remove(prefix.toBinaryString())) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700527 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700528 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700529 * If no entry was removed, the <prefix, nexthop> wasn't there so
530 * it's probably already been removed and we don't need to do anything
531 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700532 executeDeleteRoute(prefix, update.getRibEntry());
533
Jonathan Hart938a0152014-04-07 18:27:31 -0700534 }
Jonathan Hart43f28742014-08-22 16:34:05 -0700535
536 prefixesWaitingOnArp.removeAll(prefix.getInetAddress());
537 // TODO cancel the request in the ARP manager as well
Ray Milkey269ffb92014-04-03 14:43:30 -0700538 }
539 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700540
Ray Milkey269ffb92014-04-03 14:43:30 -0700541 /**
pingping-lin1ada7ce2014-08-14 13:45:22 -0700542 * Delete prefix intent installed.
543 *
544 * @param prefix IP prefix withdrew in a rib update announcement
545 * @param ribEntry next hop information
Ray Milkey269ffb92014-04-03 14:43:30 -0700546 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700547 private void executeDeleteRoute(Prefix prefix, RibEntry ribEntry) {
548 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700549
pingping-lin1ada7ce2014-08-14 13:45:22 -0700550 MultiPointToSinglePointIntent intent = pushedRouteIntents.remove(prefix);
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700551
pingping-lin1ada7ce2014-08-14 13:45:22 -0700552 if (intent == null) {
553 log.debug("There is no intent in pushedRouteIntents to delete for " +
554 "prefix: {}", prefix);
555 } else {
556 intentService.withdraw(intent);
557 log.debug("Deleted the pushedRouteIntent for prefix: {}", prefix);
Ray Milkey269ffb92014-04-03 14:43:30 -0700558 }
Komal Shah399a2922014-05-28 01:57:40 -0700559 }
560
Ray Milkey269ffb92014-04-03 14:43:30 -0700561 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700562 * Setup the Paths to the BGP Daemon. Run a loop for all of the bgpPeers
563 * Push flow from BGPd to the peer Push flow from peer to BGPd Parameters to
564 * pass to the intent are as follows: String id, long srcSwitch, long
565 * srcPort, long srcMac, int srcIP, long dstSwitch, long dstPort, long
566 * dstMac, int dstIP
Komal Shah399a2922014-05-28 01:57:40 -0700567 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700568 private void setupBgpPaths() {
Komal Shah399a2922014-05-28 01:57:40 -0700569 IntentOperationList operations = new IntentOperationList();
570 for (BgpPeer bgpPeer : bgpPeers.values()) {
571 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700572 // Inet4Address.
Komal Shah399a2922014-05-28 01:57:40 -0700573 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
574 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700575 String fwdIntentId = caller + ":"
576 + controllerRegistryService.getNextUniqueId();
577 String bwdIntentId = caller + ":"
578 + controllerRegistryService.getNextUniqueId();
Komal Shah399a2922014-05-28 01:57:40 -0700579 SwitchPort srcPort =
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700580 new SwitchPort(bgpdAttachmentPoint.getDpid(),
581 bgpdAttachmentPoint.getPortNumber());
pingping-lin1ada7ce2014-08-14 13:45:22 -0700582 // TODO: replace the code below with peerInterface.getSwitchPort()
583 // when using poingToPointIntent
Komal Shah399a2922014-05-28 01:57:40 -0700584 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700585 new SwitchPort(new Dpid(peerInterface.getDpid()),
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700586 new PortNumber(peerInterface.getSwitchPort().getPortNumber()));
pingping-lin1ada7ce2014-08-14 13:45:22 -0700587
588 // TODO: add TCP port number 179 into intent for BGP
589
Komal Shah399a2922014-05-28 01:57:40 -0700590 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700591 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700592 ShortestPathIntent.EMPTYMACADDRESS, srcIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700593 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700594 ShortestPathIntent.EMPTYMACADDRESS, dstIP);
Komal Shah399a2922014-05-28 01:57:40 -0700595 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700596 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700597 ShortestPathIntent.EMPTYMACADDRESS, dstIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700598 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700599 ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700600 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
601 operations.add(operator, fwdIntent);
602 operations.add(operator, bwdIntent);
603 }
604 pathRuntime.executeIntentOperations(operations);
605 }
606
pingping-lin1ada7ce2014-08-14 13:45:22 -0700607 /**
608 * This method handles the prefixes which are waiting for ARP replies for
609 * MAC addresses of next hops.
610 *
611 * @param ipAddress next hop router IP address, for which we sent ARP request out
612 * @param macAddress MAC address which is relative to the ipAddress
613 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700614 @Override
615 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
616 log.debug("Received ARP response: {} => {}",
617 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700618
Ray Milkey269ffb92014-04-03 14:43:30 -0700619 /*
pingping-lin1ada7ce2014-08-14 13:45:22 -0700620 * We synchronize on this to prevent changes to the InvertedRadixTree
621 * while we're pushing intent. If the InvertedRadixTree changes, the
622 * InvertedRadixTree and intent could get out of sync.
Ray Milkey269ffb92014-04-03 14:43:30 -0700623 */
624 synchronized (this) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700625
pingping-lin1ada7ce2014-08-14 13:45:22 -0700626 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700627
Ray Milkey269ffb92014-04-03 14:43:30 -0700628 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700629 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700630
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700631 RibEntry rib = bgpRoutes.getValueForExactKey(
632 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700633 if (rib != null && rib.equals(update.getRibEntry())) {
634 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
635 rib.getNextHop().getHostAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700636 // We only push prefix flows if the prefix is still in the
pingping-lin1ada7ce2014-08-14 13:45:22 -0700637 // InvertedRadixTree and the next hop is the same as our update.
638 // The prefix could have been removed while we were waiting
639 // for the ARP, or the next hop could have changed.
Jonathan Hart43f28742014-08-22 16:34:05 -0700640 addRouteIntentToNextHop(update.getPrefix(), ipAddress,
641 macAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700642 } else {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700643 log.debug("Received ARP response, but {},{} is no longer in " +
644 "InvertedRadixTree", update.getPrefix(),
645 update.getRibEntry());
Ray Milkey269ffb92014-04-03 14:43:30 -0700646 }
647 }
648 }
649 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700650
pingping-lin1ada7ce2014-08-14 13:45:22 -0700651
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700652 /*private void setupArpFlows() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700653 OFMatch match = new OFMatch();
654 match.setDataLayerType(Ethernet.TYPE_ARP);
655 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700656
Ray Milkey269ffb92014-04-03 14:43:30 -0700657 OFFlowMod fm = new OFFlowMod();
658 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700659
Ray Milkey269ffb92014-04-03 14:43:30 -0700660 OFActionOutput action = new OFActionOutput();
661 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
662 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700663 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700664 actions.add(action);
665 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700666
Ray Milkey269ffb92014-04-03 14:43:30 -0700667 fm.setIdleTimeout((short) 0)
668 .setHardTimeout((short) 0)
669 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
670 .setCookie(0)
671 .setCommand(OFFlowMod.OFPFC_ADD)
672 .setPriority(ARP_PRIORITY)
673 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700674
Ray Milkey269ffb92014-04-03 14:43:30 -0700675 for (String strdpid : switches) {
676 flowCache.write(HexString.toLong(strdpid), fm);
677 }
678 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700679
Ray Milkey269ffb92014-04-03 14:43:30 -0700680 private void setupDefaultDropFlows() {
681 OFFlowMod fm = new OFFlowMod();
682 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -0700683 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700684
Ray Milkey269ffb92014-04-03 14:43:30 -0700685 fm.setIdleTimeout((short) 0)
686 .setHardTimeout((short) 0)
687 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
688 .setCookie(0)
689 .setCommand(OFFlowMod.OFPFC_ADD)
690 .setPriority((short) 0)
691 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700692
Ray Milkey269ffb92014-04-03 14:43:30 -0700693 OFFlowMod fmLLDP;
694 OFFlowMod fmBDDP;
695 try {
696 fmLLDP = fm.clone();
697 fmBDDP = fm.clone();
698 } catch (CloneNotSupportedException e1) {
699 log.error("Error cloning flow mod", e1);
700 return;
701 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700702
Ray Milkey269ffb92014-04-03 14:43:30 -0700703 OFMatch matchLLDP = new OFMatch();
704 matchLLDP.setDataLayerType((short) 0x88cc);
705 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
706 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700707
Ray Milkey269ffb92014-04-03 14:43:30 -0700708 OFMatch matchBDDP = new OFMatch();
709 matchBDDP.setDataLayerType((short) 0x8942);
710 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
711 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700712
Ray Milkey269ffb92014-04-03 14:43:30 -0700713 OFActionOutput action = new OFActionOutput();
714 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
715 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700716 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700717 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700718
Ray Milkey269ffb92014-04-03 14:43:30 -0700719 fmLLDP.setActions(actions);
720 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700721
Ray Milkey269ffb92014-04-03 14:43:30 -0700722 fmLLDP.setPriority(ARP_PRIORITY);
723 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
724 fmBDDP.setPriority(ARP_PRIORITY);
725 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700726
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700727 List<OFFlowMod> flowModList = new ArrayList<>(3);
Ray Milkey269ffb92014-04-03 14:43:30 -0700728 flowModList.add(fm);
729 flowModList.add(fmLLDP);
730 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700731
Ray Milkey269ffb92014-04-03 14:43:30 -0700732 for (String strdpid : switches) {
733 flowCache.write(HexString.toLong(strdpid), flowModList);
734 }
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700735 }*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700736
pingping-lin1ada7ce2014-08-14 13:45:22 -0700737 /**
738 * The SDN-IP application is started from this method.
739 */
740 @Override
741 public void beginRouting() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700742 log.debug("Topology is now ready, beginning routing function");
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700743
pingping-lin1ada7ce2014-08-14 13:45:22 -0700744 // TODO
Ray Milkey269ffb92014-04-03 14:43:30 -0700745 /*setupArpFlows();
746 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700747
pingping-lin1ada7ce2014-08-14 13:45:22 -0700748 setupBgpPaths();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700749
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700750 // Suppress link discovery on external-facing router ports
Ray Milkey269ffb92014-04-03 14:43:30 -0700751 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -0700752 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -0700753 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700754
Ray Milkey269ffb92014-04-03 14:43:30 -0700755 bgpUpdatesExecutor.execute(new Runnable() {
756 @Override
757 public void run() {
758 doUpdatesThread();
759 }
760 });
761 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700762
pingping-lin1ada7ce2014-08-14 13:45:22 -0700763 /**
764 * Thread for handling RIB updates.
765 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700766 private void doUpdatesThread() {
767 boolean interrupted = false;
768 try {
769 while (true) {
770 try {
771 RibUpdate update = ribUpdates.take();
772 switch (update.getOperation()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700773 case UPDATE:
774 if (validateUpdate(update)) {
775 processRibAdd(update);
776 } else {
777 log.debug("Rib UPDATE out of order: {} via {}",
778 update.getPrefix(), update.getRibEntry().getNextHop());
779 }
780 break;
781 case DELETE:
782 if (validateUpdate(update)) {
783 processRibDelete(update);
784 } else {
785 log.debug("Rib DELETE out of order: {} via {}",
786 update.getPrefix(), update.getRibEntry().getNextHop());
787 }
788 break;
789 default:
790 log.error("Unknown operation {}", update.getOperation());
791 break;
Ray Milkey269ffb92014-04-03 14:43:30 -0700792 }
793 } catch (InterruptedException e) {
794 log.debug("Interrupted while taking from updates queue", e);
795 interrupted = true;
796 } catch (Exception e) {
797 log.debug("exception", e);
798 }
799 }
800 } finally {
801 if (interrupted) {
802 Thread.currentThread().interrupt();
803 }
804 }
805 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700806
pingping-lin1ada7ce2014-08-14 13:45:22 -0700807 /**
808 * Judge whether a RIB update is in correct order.
809 *
810 * @param update RIB update
811 * @return boolean whether the RIB update is in in correct order
812 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700813 private boolean validateUpdate(RibUpdate update) {
814 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700815 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
816 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700817
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700818 // If there is no existing entry we must assume this is the most recent
819 // update. However this might not always be the case as we might have a
820 // POST then DELETE reordering.
821 // if (oldEntry == null ||
822 // !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700823 if (oldEntry == null) {
824 return true;
825 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700826
Ray Milkey269ffb92014-04-03 14:43:30 -0700827 // This handles the case where routes are gathered in the initial
828 // request because they don't have sequence number info
829 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
830 return true;
831 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700832
Ray Milkey269ffb92014-04-03 14:43:30 -0700833 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
834 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -0700835 }
Ray Milkey4985f212014-04-10 16:57:05 -0700836
837 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700838 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -0700839 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800840
pingping-lin1ada7ce2014-08-14 13:45:22 -0700841 /**
842 * To find the Interface which has longest matchable IP prefix (sub-network
843 * prefix) to next hop IP address.
844 *
845 * @param address the IP address of next hop router
846 * @return Interface the Interface which has longest matchable IP prefix
847 */
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700848 private Interface longestInterfacePrefixMatch(InetAddress address) {
849 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
850 Prefix.MAX_PREFIX_LENGTH);
851 Iterator<Interface> it =
852 interfaceRoutes.getValuesForKeysPrefixing(
853 prefixToSearchFor.toBinaryString()).iterator();
854 Interface intf = null;
855 // Find the last prefix, which will be the longest prefix
856 while (it.hasNext()) {
857 intf = it.next();
858 }
859
860 return intf;
861 }
862
Ray Milkey269ffb92014-04-03 14:43:30 -0700863 /*
864 * IConfigInfoService methods
865 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700866
Ray Milkey269ffb92014-04-03 14:43:30 -0700867 @Override
868 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700869 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -0700870 return (intf != null && intf.getIpAddress().equals(address));
871 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700872
Ray Milkey269ffb92014-04-03 14:43:30 -0700873 @Override
874 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700875 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -0700876 return (intf != null && !intf.getIpAddress().equals(address));
877 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700878
Ray Milkey269ffb92014-04-03 14:43:30 -0700879 @Override
880 public boolean fromExternalNetwork(long inDpid, short inPort) {
881 for (Interface intf : interfaces.values()) {
882 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
883 return true;
884 }
885 }
886 return false;
887 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700888
pingping-lin1ada7ce2014-08-14 13:45:22 -0700889 /**
890 * To find the relative egress Interface for a next hop IP address.
891 *
892 * @param dstIpAddress the IP address of next hop router
893 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700894 @Override
895 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700896 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700897 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700898
Ray Milkey269ffb92014-04-03 14:43:30 -0700899 @Override
900 public boolean hasLayer3Configuration() {
901 return !interfaces.isEmpty();
902 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700903
Ray Milkey269ffb92014-04-03 14:43:30 -0700904 @Override
905 public MACAddress getRouterMacAddress() {
906 return bgpdMacAddress;
907 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700908
Ray Milkey269ffb92014-04-03 14:43:30 -0700909 @Override
910 public short getVlan() {
911 return vlan;
912 }
pingping-lin1ada7ce2014-08-14 13:45:22 -0700913
pingping-lin0426dee2014-08-27 15:03:17 -0700914 @Override
915 public Set<SwitchPort> getExternalSwitchPorts() {
916 return Collections.unmodifiableSet(externalNetworkSwitchPorts);
917 }
918
pingping-lina2cbfad2013-03-07 08:39:21 +0800919}