blob: 35c3eaa277b9d01700b73e7be7db208b9f8576fc [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-lina2cbfad2013-03-07 08:39:21 +08008import java.util.HashMap;
pingping-lin1ada7ce2014-08-14 13:45:22 -07009import java.util.HashSet;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070010import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070011import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070012import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120013import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120014import java.util.concurrent.BlockingQueue;
pingping-lin1ada7ce2014-08-14 13:45:22 -070015import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120016import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120017import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120018import java.util.concurrent.LinkedBlockingQueue;
pingping-lina2cbfad2013-03-07 08:39:21 +080019
20import net.floodlightcontroller.core.module.FloodlightModuleContext;
21import net.floodlightcontroller.core.module.FloodlightModuleException;
22import net.floodlightcontroller.core.module.IFloodlightModule;
23import net.floodlightcontroller.core.module.IFloodlightService;
pingping-lina2cbfad2013-03-07 08:39:21 +080024import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120025import net.floodlightcontroller.util.MACAddress;
pingping-lin1ada7ce2014-08-14 13:45:22 -070026import net.onrc.onos.api.newintent.IntentService;
27import net.onrc.onos.api.newintent.MultiPointToSinglePointIntent;
Jonathan Hart0961fe82014-04-03 09:56:25 -070028import net.onrc.onos.apps.proxyarp.IArpRequester;
29import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart8f6dc092014-04-18 15:56:43 -070030import net.onrc.onos.apps.sdnip.RibUpdate.Operation;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070031import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutable;
Komal Shah399a2922014-05-28 01:57:40 -070032import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutableNew;
33import net.onrc.onos.core.intent.IntentOperation;
34import net.onrc.onos.core.intent.IntentOperationList;
35import net.onrc.onos.core.intent.ShortestPathIntent;
36import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
Jonathan Harta99ec672014-04-03 11:30:34 -070037import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070038import net.onrc.onos.core.main.config.IConfigInfoService;
pingping-lin1ada7ce2014-08-14 13:45:22 -070039import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
40import net.onrc.onos.core.matchaction.match.PacketMatch;
41import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
42import net.onrc.onos.core.newintent.IdBlockAllocatorBasedIntentIdGenerator;
Komal Shah399a2922014-05-28 01:57:40 -070043import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart23701d12014-04-03 10:45:48 -070044import net.onrc.onos.core.util.Dpid;
pingping-lin1ada7ce2014-08-14 13:45:22 -070045import net.onrc.onos.core.util.IPv4;
Yuta HIGUCHIfb564502014-06-16 21:29:00 -070046import net.onrc.onos.core.util.PortNumber;
Jonathan Hart23701d12014-04-03 10:45:48 -070047import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080048import net.sf.json.JSONArray;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070049import net.sf.json.JSONException;
pingping-line2a09ca2013-03-23 09:33:58 +080050import net.sf.json.JSONObject;
51import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080052
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070053import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120054import org.codehaus.jackson.JsonParseException;
55import org.codehaus.jackson.map.JsonMappingException;
56import org.codehaus.jackson.map.ObjectMapper;
pingping-lina2cbfad2013-03-07 08:39:21 +080057import org.slf4j.Logger;
58import org.slf4j.LoggerFactory;
59
Jonathan Hart4dfc3652013-08-02 20:22:36 +120060import com.google.common.collect.HashMultimap;
61import com.google.common.collect.Multimaps;
62import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120063import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120064import com.google.common.util.concurrent.ThreadFactoryBuilder;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070065import com.googlecode.concurrenttrees.radix.RadixTree;
66import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
67import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
68import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120069
pingping-lin1ada7ce2014-08-14 13:45:22 -070070/**
71 * This class sets up BGP paths, handles RIB updates and relative intents.
72 * TODO: Thread-safe.
73 */
Jonathan Hart8f6dc092014-04-18 15:56:43 -070074public class SdnIp implements IFloodlightModule, ISdnIpService,
pingping-lin1ada7ce2014-08-14 13:45:22 -070075 IArpRequester, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070076
Jonathan Hart8f6dc092014-04-18 15:56:43 -070077 private static final Logger log = LoggerFactory.getLogger(SdnIp.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080078
Ray Milkey269ffb92014-04-03 14:43:30 -070079 private ILinkDiscoveryService linkDiscoveryService;
80 private IRestApiService restApi;
81 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070082
Jonathan Hartf6978ce2014-06-23 11:20:04 -070083 private InvertedRadixTree<RibEntry> bgpRoutes;
84 private InvertedRadixTree<Interface> interfaceRoutes;
85
Ray Milkey269ffb92014-04-03 14:43:30 -070086 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070087
Ray Milkey269ffb92014-04-03 14:43:30 -070088 private String bgpdRestIp;
89 private String routerId;
Ray Milkey5df613b2014-04-15 10:50:56 -070090 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
91 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070092
Komal Shah399a2922014-05-28 01:57:40 -070093 /* ShortestPath Intent Variables */
Sho SHIMIZU9ec39822014-07-10 17:15:12 -070094 private final String caller = "SdnIp";
Komal Shah399a2922014-05-28 01:57:40 -070095 private IControllerRegistryService controllerRegistryService;
pingping-lin1ada7ce2014-08-14 13:45:22 -070096 private IntentService intentService;
Komal Shah399a2922014-05-28 01:57:40 -070097 private IPathCalcRuntimeService pathRuntime;
98 /* Shortest Intent Path Variables */
pingping-lin1ada7ce2014-08-14 13:45:22 -070099 private IdBlockAllocatorBasedIntentIdGenerator intentIdGenerator;
100 //private static final short ARP_PRIORITY = 20;
Komal Shah399a2922014-05-28 01:57:40 -0700101
pingping-lin1ada7ce2014-08-14 13:45:22 -0700102 //private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700103
Jonathan Hart938a0152014-04-07 18:27:31 -0700104 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700105 private List<String> switches;
106 private Map<String, Interface> interfaces;
107 private Map<InetAddress, BgpPeer> bgpPeers;
108 private SwitchPort bgpdAttachmentPoint;
109 private MACAddress bgpdMacAddress;
110 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700111
Ray Milkey269ffb92014-04-03 14:43:30 -0700112 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700113
Ray Milkey269ffb92014-04-03 14:43:30 -0700114 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700115
pingping-lin1ada7ce2014-08-14 13:45:22 -0700116 private ConcurrentHashMap<Prefix, MultiPointToSinglePointIntent> pushedRouteIntents;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700117
pingping-lin1ada7ce2014-08-14 13:45:22 -0700118 /**
119 * SDN-IP application has a configuration file. This method is to read all
120 * the info from this file.
121 *
122 * @param configFilename the name of configuration file for SDN-IP application
123 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700124 private void readConfiguration(String configFilename) {
125 File gatewaysFile = new File(configFilename);
126 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700127
Ray Milkey269ffb92014-04-03 14:43:30 -0700128 try {
129 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700130
Ray Milkey269ffb92014-04-03 14:43:30 -0700131 switches = config.getSwitches();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700132 interfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700133 for (Interface intf : config.getInterfaces()) {
134 interfaces.put(intf.getName(), intf);
135 }
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700136 bgpPeers = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700137 for (BgpPeer peer : config.getPeers()) {
138 bgpPeers.put(peer.getIpAddress(), peer);
139 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700140
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 bgpdAttachmentPoint = new SwitchPort(
142 new Dpid(config.getBgpdAttachmentDpid()),
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700143 PortNumber.uint16(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700144
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 bgpdMacAddress = config.getBgpdMacAddress();
146 vlan = config.getVlan();
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -0700147 } catch (JsonParseException | JsonMappingException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700148 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700149 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700150 } catch (IOException e) {
151 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700152 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700153 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700154
pingping-lin1ada7ce2014-08-14 13:45:22 -0700155 // Populate the interface InvertedRadixTree
Ray Milkey269ffb92014-04-03 14:43:30 -0700156 for (Interface intf : interfaces.values()) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700157 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
158 intf.getPrefixLength());
159 interfaceRoutes.put(prefix.toBinaryString(), intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700160 }
161 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700162
Ray Milkey269ffb92014-04-03 14:43:30 -0700163 @Override
164 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700165 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700166 l.add(ISdnIpService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700167 l.add(IConfigInfoService.class);
168 return l;
169 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700170
Ray Milkey269ffb92014-04-03 14:43:30 -0700171 @Override
172 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700173 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700174 m.put(ISdnIpService.class, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700175 m.put(IConfigInfoService.class, this);
176 return m;
177 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800178
Ray Milkey269ffb92014-04-03 14:43:30 -0700179 @Override
180 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700181 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700182 l.add(IRestApiService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700183 l.add(IControllerRegistryService.class);
184 l.add(IPathCalcRuntimeService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700185 return l;
186 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700187
Ray Milkey269ffb92014-04-03 14:43:30 -0700188 @Override
189 public void init(FloodlightModuleContext context)
190 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700191
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700192 bgpRoutes = new ConcurrentInvertedRadixTree<>(
193 new DefaultByteArrayNodeFactory());
194 interfaceRoutes = new ConcurrentInvertedRadixTree<>(
195 new DefaultByteArrayNodeFactory());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700196
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700197 ribUpdates = new LinkedBlockingQueue<>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700198
pingping-lin1ada7ce2014-08-14 13:45:22 -0700199 // Register REST handler.
Ray Milkey269ffb92014-04-03 14:43:30 -0700200 restApi = context.getServiceImpl(IRestApiService.class);
201 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800202
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700203 controllerRegistryService = context
204 .getServiceImpl(IControllerRegistryService.class);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700205
pingping-lin1ada7ce2014-08-14 13:45:22 -0700206 intentIdGenerator = new IdBlockAllocatorBasedIntentIdGenerator(
207 controllerRegistryService);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700208
pingping-lin1ada7ce2014-08-14 13:45:22 -0700209 // TODO: initialize intentService
210
211 pushedRouteIntents = new ConcurrentHashMap<>();
212
Ray Milkey269ffb92014-04-03 14:43:30 -0700213 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
214 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700215
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700216 //flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700217
Ray Milkey269ffb92014-04-03 14:43:30 -0700218 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
219 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700220
Jonathan Hart938a0152014-04-07 18:27:31 -0700221 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700222 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
223 if (bgpdRestIp == null) {
224 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700225 throw new ConfigurationRuntimeException(
226 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700227 } else {
228 log.info("BgpdRestIp set to {}", bgpdRestIp);
229 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700230
Ray Milkey269ffb92014-04-03 14:43:30 -0700231 routerId = context.getConfigParams(this).get("RouterId");
232 if (routerId == null) {
233 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700234 throw new ConfigurationRuntimeException(
235 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700236 } else {
237 log.info("RouterId set to {}", routerId);
238 }
pingping-linba5c52f2014-02-11 16:52:01 -0800239
Ray Milkey269ffb92014-04-03 14:43:30 -0700240 String configFilenameParameter = context.getConfigParams(this).get("configfile");
241 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700242 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700243 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700244 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700245
Ray Milkey5df613b2014-04-15 10:50:56 -0700246 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700247 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700248
Ray Milkey269ffb92014-04-03 14:43:30 -0700249 @Override
250 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700251 restApi.addRestletRoutable(new SdnIpWebRoutable());
Komal Shah399a2922014-05-28 01:57:40 -0700252 restApi.addRestletRoutable(new SdnIpWebRoutableNew());
pingping-linba5c52f2014-02-11 16:52:01 -0800253
Jonathan Hart938a0152014-04-07 18:27:31 -0700254 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700255 retrieveRib();
256 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800257
Ray Milkey269ffb92014-04-03 14:43:30 -0700258 @Override
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700259 public RadixTree<RibEntry> getPtree() {
260 return bgpRoutes;
Ray Milkey269ffb92014-04-03 14:43:30 -0700261 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700262
Ray Milkey269ffb92014-04-03 14:43:30 -0700263 @Override
264 public void clearPtree() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700265 log.warn("Clear table operation not supported");
Ray Milkey269ffb92014-04-03 14:43:30 -0700266 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700267
Ray Milkey269ffb92014-04-03 14:43:30 -0700268 @Override
Jonathan Hart31e15f12014-04-10 10:33:00 -0700269 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700270 return bgpdRestIp;
271 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700272
Ray Milkey269ffb92014-04-03 14:43:30 -0700273 @Override
274 public String getRouterId() {
275 return routerId;
276 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700277
pingping-lin1ada7ce2014-08-14 13:45:22 -0700278 /**
279 * SDN-IP application will fetch all rib entries from BGPd when it starts.
280 * Especially when we restart SDN-IP application while the BGPd has been
281 * running all the time. Then before SDN-IP application re-connects to BGPd,
282 * there are already lots of rib entries in BGPd.
283 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700284 private void retrieveRib() {
285 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
286 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700287
Jonathan Hart938a0152014-04-07 18:27:31 -0700288 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700289 return;
290 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700291
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700292 try {
293 response = response.replaceAll("\"", "'");
294 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
295 JSONArray ribArray = jsonObj.getJSONArray("rib");
296 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700297
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700298 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700299
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700300 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700301
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700302 for (int j = 0; j < size; j++) {
303 JSONObject ribEntry = ribArray.getJSONObject(j);
304 String prefix = ribEntry.getString("prefix");
305 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700306
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700307 // Insert each rib entry into the local rib
308 String[] substring = prefix.split("/");
309 String prefix1 = substring[0];
310 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700311
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700312 Prefix p;
313 try {
314 p = new Prefix(prefix1, Integer.parseInt(mask1));
315 } catch (NumberFormatException e) {
316 log.warn("Wrong mask format in RIB JSON: {}", mask1);
317 continue;
318 } catch (IllegalArgumentException e1) {
319 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
320 continue;
321 }
322
323 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
324
325 try {
326 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
327 } catch (InterruptedException e) {
328 log.debug("Interrupted while pushing onto update queue");
329 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700330 }
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700331 } catch (JSONException e) {
332 // TODO don't parse JSON manually
333 log.error("Error parsing inital route table JSON:", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700334 }
335 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700336
pingping-lin1ada7ce2014-08-14 13:45:22 -0700337 /**
338 * Put RIB update to RIB update queue.
339 *
340 * @param update RIB update
341 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700342 @Override
343 public void newRibUpdate(RibUpdate update) {
344 try {
345 ribUpdates.put(update);
346 } catch (InterruptedException e) {
347 log.debug("Interrupted while putting on ribUpdates queue", e);
348 Thread.currentThread().interrupt();
349 }
350 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700351
pingping-lin1ada7ce2014-08-14 13:45:22 -0700352 /**
353 * Process adding RIB update.
354 * Put new RIB update into InvertedRadixTree. If there was an existing nexthop
355 * for this prefix, but the next hop was different, then execute deleting old
356 * RIB update. If the next hop is the SDN domain, we do not handle it at the
357 * moment. Otherwise, execute adding RIB.
358 *
359 * @param update RIB update
360 */
Sho SHIMIZUba372192014-07-10 08:59:57 -0700361 private void processRibAdd(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700362 synchronized (this) {
363 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700364
Jonathan Hart938a0152014-04-07 18:27:31 -0700365 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700366
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700367 RibEntry rib = bgpRoutes.put(prefix.toBinaryString(), update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700368
Jonathan Hart938a0152014-04-07 18:27:31 -0700369 if (rib != null && !rib.equals(update.getRibEntry())) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700370 // There was an existing nexthop for this prefix. This update
pingping-lin1ada7ce2014-08-14 13:45:22 -0700371 // supersedes that, so we need to remove the old flows for this
372 // prefix from the switches
373 executeDeleteRoute(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700374 }
Ray Milkey5d406012014-04-08 14:44:41 -0700375
Jonathan Hart938a0152014-04-07 18:27:31 -0700376 if (update.getRibEntry().getNextHop().equals(
377 InetAddresses.forString("0.0.0.0"))) {
378 // Route originated by SDN domain
379 // We don't handle these at the moment
380 log.debug("Own route {} to {}", prefix,
381 update.getRibEntry().getNextHop().getHostAddress());
382 return;
383 }
Ray Milkey5d406012014-04-08 14:44:41 -0700384
Ray Milkey7531a342014-04-11 15:08:12 -0700385 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700386 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700387 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700388
pingping-lin1ada7ce2014-08-14 13:45:22 -0700389 /**
390 * Execute adding RIB update.
391 * Find out the egress Interface and MAC address of next hop router for this
392 * RIB update. If the MAC address can not be found in ARP cache, then this
393 * prefix will be put in prefixesWaitingOnArp queue. Otherwise, new flow
394 * intent will be created and installed.
395 *
396 * @param update RIB update
397 */
Ray Milkey7531a342014-04-11 15:08:12 -0700398 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700399
Ray Milkey269ffb92014-04-03 14:43:30 -0700400 Prefix prefix = update.getPrefix();
401 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700402
pingping-lin1ada7ce2014-08-14 13:45:22 -0700403 InetAddress nextHopIpAddress = rib.getNextHop();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700404
Ray Milkey269ffb92014-04-03 14:43:30 -0700405 // Find the attachment point (egress interface) of the next hop
406 Interface egressInterface = null;
pingping-lin1ada7ce2014-08-14 13:45:22 -0700407
408 if (bgpPeers.containsKey(nextHopIpAddress)) {
409 // Route to a peer
410 log.debug("Route to peer {}", nextHopIpAddress);
411 BgpPeer peer = bgpPeers.get(nextHopIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700412 egressInterface = interfaces.get(peer.getInterfaceName());
413 } else {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700414 // Route to non-peer
415 log.debug("Route to non-peer {}", nextHopIpAddress);
416 egressInterface = getOutgoingInterface(nextHopIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700417 if (egressInterface == null) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700418 log.warn("No outgoing interface found for {}", nextHopIpAddress
419 .getHostAddress());
Ray Milkey269ffb92014-04-03 14:43:30 -0700420 return;
421 }
422 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700423
pingping-lin1ada7ce2014-08-14 13:45:22 -0700424 // See if we know the MAC address of the next hop
425 MACAddress nextHopMacAddress = proxyArp.getMacAddress(nextHopIpAddress);
426
Ray Milkey269ffb92014-04-03 14:43:30 -0700427 if (nextHopMacAddress == null) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700428 prefixesWaitingOnArp.put(nextHopIpAddress,
Ray Milkey269ffb92014-04-03 14:43:30 -0700429 new RibUpdate(Operation.UPDATE, prefix, rib));
pingping-lin1ada7ce2014-08-14 13:45:22 -0700430 proxyArp.sendArpRequest(nextHopIpAddress, this, true);
Ray Milkey269ffb92014-04-03 14:43:30 -0700431 return;
432 } else {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700433
pingping-lin1ada7ce2014-08-14 13:45:22 -0700434 //For all prefixes we need to add a intent for each of them
435 addRouteIntent(prefix, egressInterface, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700436
Ray Milkey269ffb92014-04-03 14:43:30 -0700437 }
pingping-lin1ada7ce2014-08-14 13:45:22 -0700438
Ray Milkey269ffb92014-04-03 14:43:30 -0700439 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700440
Ray Milkey269ffb92014-04-03 14:43:30 -0700441 /**
pingping-lin1ada7ce2014-08-14 13:45:22 -0700442 * Install a flow intent for a prefix.
443 * Intent will match dst IP prefix and rewrite dst MAC address at all other
444 * border switches, then forward packets according to dst MAC address.
445 *
446 * @param prefix IP prefix from BGP route
447 * @param egressInterface egress Interface connected to next hop router
448 * @param nextHopMacAddress MAC address of next hop router
Ray Milkey269ffb92014-04-03 14:43:30 -0700449 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700450 private void addRouteIntent(Prefix prefix, Interface egressInterface,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700451 MACAddress nextHopMacAddress) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700452 log.debug("Adding intent for prefix {}, next hop mac {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700453 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700454
pingping-lin1ada7ce2014-08-14 13:45:22 -0700455 MultiPointToSinglePointIntent pushedIntent = pushedRouteIntents.get(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700456
pingping-lin1ada7ce2014-08-14 13:45:22 -0700457 // Just for testing.
458 if (pushedIntent != null) {
459 log.error("There should not be a pushed intent: {}", pushedIntent);
460 }
pingping-linba5c52f2014-02-11 16:52:01 -0800461
pingping-lin1ada7ce2014-08-14 13:45:22 -0700462 SwitchPort egressPort = egressInterface.getSwitchPort();
pingping-linba5c52f2014-02-11 16:52:01 -0800463
pingping-lin1ada7ce2014-08-14 13:45:22 -0700464 Set<SwitchPort> ingressPorts = new HashSet<SwitchPort>();
pingping-linba5c52f2014-02-11 16:52:01 -0800465
Ray Milkey269ffb92014-04-03 14:43:30 -0700466 for (Interface intf : interfaces.values()) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700467 if (!intf.equals(egressInterface)) {
468 SwitchPort srcPort = intf.getSwitchPort();
469 ingressPorts.add(srcPort);
Ray Milkey269ffb92014-04-03 14:43:30 -0700470 }
471 }
pingping-linba5c52f2014-02-11 16:52:01 -0800472
pingping-lin1ada7ce2014-08-14 13:45:22 -0700473 // Match the destination IP prefix at the first hop
474 PacketMatchBuilder builder = new PacketMatchBuilder();
475 builder.setDstIp(new IPv4(InetAddresses
476 .coerceToInteger(prefix.getInetAddress())),
477 (short) prefix.getPrefixLength());
478 PacketMatch packetMatch = builder.build();
pingping-linba5c52f2014-02-11 16:52:01 -0800479
pingping-lin1ada7ce2014-08-14 13:45:22 -0700480 // Rewrite the destination MAC address
481 ModifyDstMacAction modifyDstMacAction =
482 new ModifyDstMacAction(nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800483
pingping-lin1ada7ce2014-08-14 13:45:22 -0700484 MultiPointToSinglePointIntent intent =
485 new MultiPointToSinglePointIntent(intentIdGenerator.getNewId(),
486 packetMatch, modifyDstMacAction, ingressPorts, egressPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800487
pingping-lin1ada7ce2014-08-14 13:45:22 -0700488 intentService.submit(intent);
pingping-linba5c52f2014-02-11 16:52:01 -0800489
pingping-lin1ada7ce2014-08-14 13:45:22 -0700490 // Maintain the Intent
491 pushedRouteIntents.put(prefix, intent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700492 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700493
pingping-lin1ada7ce2014-08-14 13:45:22 -0700494 /**
495 * Remove prefix from InvertedRadixTree, if success, then try to delete the
496 * relative intent.
497 *
498 * @param update RIB update
499 */
Sho SHIMIZUba372192014-07-10 08:59:57 -0700500 private void processRibDelete(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700501 synchronized (this) {
502 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700503
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700504 // if (ptree.remove(prefix, update.getRibEntry())) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700505
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700506 // TODO check the change of logic here - remove doesn't check that
pingping-lin1ada7ce2014-08-14 13:45:22 -0700507 // the rib entry was what we expected (and we can't do this
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700508 // concurrently)
pingping-lin1ada7ce2014-08-14 13:45:22 -0700509
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700510 if (bgpRoutes.remove(prefix.toBinaryString())) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700511 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700512 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700513 * If no entry was removed, the <prefix, nexthop> wasn't there so
514 * it's probably already been removed and we don't need to do anything
515 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700516 executeDeleteRoute(prefix, update.getRibEntry());
517
Jonathan Hart938a0152014-04-07 18:27:31 -0700518 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700519 }
520 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700521
Ray Milkey269ffb92014-04-03 14:43:30 -0700522 /**
pingping-lin1ada7ce2014-08-14 13:45:22 -0700523 * Delete prefix intent installed.
524 *
525 * @param prefix IP prefix withdrew in a rib update announcement
526 * @param ribEntry next hop information
Ray Milkey269ffb92014-04-03 14:43:30 -0700527 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700528 private void executeDeleteRoute(Prefix prefix, RibEntry ribEntry) {
529 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700530
pingping-lin1ada7ce2014-08-14 13:45:22 -0700531 MultiPointToSinglePointIntent intent = pushedRouteIntents.remove(prefix);
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700532
pingping-lin1ada7ce2014-08-14 13:45:22 -0700533 if (intent == null) {
534 log.debug("There is no intent in pushedRouteIntents to delete for " +
535 "prefix: {}", prefix);
536 } else {
537 intentService.withdraw(intent);
538 log.debug("Deleted the pushedRouteIntent for prefix: {}", prefix);
Ray Milkey269ffb92014-04-03 14:43:30 -0700539 }
Komal Shah399a2922014-05-28 01:57:40 -0700540 }
541
Ray Milkey269ffb92014-04-03 14:43:30 -0700542 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700543 * Setup the Paths to the BGP Daemon. Run a loop for all of the bgpPeers
544 * Push flow from BGPd to the peer Push flow from peer to BGPd Parameters to
545 * pass to the intent are as follows: String id, long srcSwitch, long
546 * srcPort, long srcMac, int srcIP, long dstSwitch, long dstPort, long
547 * dstMac, int dstIP
Komal Shah399a2922014-05-28 01:57:40 -0700548 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700549 private void setupBgpPaths() {
Komal Shah399a2922014-05-28 01:57:40 -0700550 IntentOperationList operations = new IntentOperationList();
551 for (BgpPeer bgpPeer : bgpPeers.values()) {
552 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700553 // Inet4Address.
Komal Shah399a2922014-05-28 01:57:40 -0700554 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
555 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700556 String fwdIntentId = caller + ":"
557 + controllerRegistryService.getNextUniqueId();
558 String bwdIntentId = caller + ":"
559 + controllerRegistryService.getNextUniqueId();
Komal Shah399a2922014-05-28 01:57:40 -0700560 SwitchPort srcPort =
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700561 new SwitchPort(bgpdAttachmentPoint.getDpid(),
562 bgpdAttachmentPoint.getPortNumber());
pingping-lin1ada7ce2014-08-14 13:45:22 -0700563 // TODO: replace the code below with peerInterface.getSwitchPort()
564 // when using poingToPointIntent
Komal Shah399a2922014-05-28 01:57:40 -0700565 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700566 new SwitchPort(new Dpid(peerInterface.getDpid()),
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700567 new PortNumber(peerInterface.getSwitchPort().getPortNumber()));
pingping-lin1ada7ce2014-08-14 13:45:22 -0700568
569 // TODO: add TCP port number 179 into intent for BGP
570
Komal Shah399a2922014-05-28 01:57:40 -0700571 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700572 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700573 ShortestPathIntent.EMPTYMACADDRESS, srcIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700574 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700575 ShortestPathIntent.EMPTYMACADDRESS, dstIP);
Komal Shah399a2922014-05-28 01:57:40 -0700576 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700577 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700578 ShortestPathIntent.EMPTYMACADDRESS, dstIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700579 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700580 ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700581 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
582 operations.add(operator, fwdIntent);
583 operations.add(operator, bwdIntent);
584 }
585 pathRuntime.executeIntentOperations(operations);
586 }
587
pingping-lin1ada7ce2014-08-14 13:45:22 -0700588 /**
589 * This method handles the prefixes which are waiting for ARP replies for
590 * MAC addresses of next hops.
591 *
592 * @param ipAddress next hop router IP address, for which we sent ARP request out
593 * @param macAddress MAC address which is relative to the ipAddress
594 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700595 @Override
596 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
597 log.debug("Received ARP response: {} => {}",
598 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700599
Ray Milkey269ffb92014-04-03 14:43:30 -0700600 /*
pingping-lin1ada7ce2014-08-14 13:45:22 -0700601 * We synchronize on this to prevent changes to the InvertedRadixTree
602 * while we're pushing intent. If the InvertedRadixTree changes, the
603 * InvertedRadixTree and intent could get out of sync.
Ray Milkey269ffb92014-04-03 14:43:30 -0700604 */
605 synchronized (this) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700606
pingping-lin1ada7ce2014-08-14 13:45:22 -0700607 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700608
Ray Milkey269ffb92014-04-03 14:43:30 -0700609 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700610 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700611
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700612 RibEntry rib = bgpRoutes.getValueForExactKey(
613 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700614 if (rib != null && rib.equals(update.getRibEntry())) {
615 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
616 rib.getNextHop().getHostAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700617 // We only push prefix flows if the prefix is still in the
pingping-lin1ada7ce2014-08-14 13:45:22 -0700618 // InvertedRadixTree and the next hop is the same as our update.
619 // The prefix could have been removed while we were waiting
620 // for the ARP, or the next hop could have changed.
Ray Milkey7531a342014-04-11 15:08:12 -0700621 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700622 } else {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700623 log.debug("Received ARP response, but {},{} is no longer in " +
624 "InvertedRadixTree", update.getPrefix(),
625 update.getRibEntry());
Ray Milkey269ffb92014-04-03 14:43:30 -0700626 }
627 }
628 }
629 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700630
pingping-lin1ada7ce2014-08-14 13:45:22 -0700631
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700632 /*private void setupArpFlows() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700633 OFMatch match = new OFMatch();
634 match.setDataLayerType(Ethernet.TYPE_ARP);
635 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700636
Ray Milkey269ffb92014-04-03 14:43:30 -0700637 OFFlowMod fm = new OFFlowMod();
638 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700639
Ray Milkey269ffb92014-04-03 14:43:30 -0700640 OFActionOutput action = new OFActionOutput();
641 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
642 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700643 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700644 actions.add(action);
645 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700646
Ray Milkey269ffb92014-04-03 14:43:30 -0700647 fm.setIdleTimeout((short) 0)
648 .setHardTimeout((short) 0)
649 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
650 .setCookie(0)
651 .setCommand(OFFlowMod.OFPFC_ADD)
652 .setPriority(ARP_PRIORITY)
653 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700654
Ray Milkey269ffb92014-04-03 14:43:30 -0700655 for (String strdpid : switches) {
656 flowCache.write(HexString.toLong(strdpid), fm);
657 }
658 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700659
Ray Milkey269ffb92014-04-03 14:43:30 -0700660 private void setupDefaultDropFlows() {
661 OFFlowMod fm = new OFFlowMod();
662 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -0700663 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700664
Ray Milkey269ffb92014-04-03 14:43:30 -0700665 fm.setIdleTimeout((short) 0)
666 .setHardTimeout((short) 0)
667 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
668 .setCookie(0)
669 .setCommand(OFFlowMod.OFPFC_ADD)
670 .setPriority((short) 0)
671 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700672
Ray Milkey269ffb92014-04-03 14:43:30 -0700673 OFFlowMod fmLLDP;
674 OFFlowMod fmBDDP;
675 try {
676 fmLLDP = fm.clone();
677 fmBDDP = fm.clone();
678 } catch (CloneNotSupportedException e1) {
679 log.error("Error cloning flow mod", e1);
680 return;
681 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700682
Ray Milkey269ffb92014-04-03 14:43:30 -0700683 OFMatch matchLLDP = new OFMatch();
684 matchLLDP.setDataLayerType((short) 0x88cc);
685 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
686 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700687
Ray Milkey269ffb92014-04-03 14:43:30 -0700688 OFMatch matchBDDP = new OFMatch();
689 matchBDDP.setDataLayerType((short) 0x8942);
690 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
691 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700692
Ray Milkey269ffb92014-04-03 14:43:30 -0700693 OFActionOutput action = new OFActionOutput();
694 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
695 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700696 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700697 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700698
Ray Milkey269ffb92014-04-03 14:43:30 -0700699 fmLLDP.setActions(actions);
700 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700701
Ray Milkey269ffb92014-04-03 14:43:30 -0700702 fmLLDP.setPriority(ARP_PRIORITY);
703 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
704 fmBDDP.setPriority(ARP_PRIORITY);
705 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700706
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700707 List<OFFlowMod> flowModList = new ArrayList<>(3);
Ray Milkey269ffb92014-04-03 14:43:30 -0700708 flowModList.add(fm);
709 flowModList.add(fmLLDP);
710 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700711
Ray Milkey269ffb92014-04-03 14:43:30 -0700712 for (String strdpid : switches) {
713 flowCache.write(HexString.toLong(strdpid), flowModList);
714 }
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700715 }*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700716
pingping-lin1ada7ce2014-08-14 13:45:22 -0700717 /**
718 * The SDN-IP application is started from this method.
719 */
720 @Override
721 public void beginRouting() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700722 log.debug("Topology is now ready, beginning routing function");
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700723
pingping-lin1ada7ce2014-08-14 13:45:22 -0700724 // TODO
Ray Milkey269ffb92014-04-03 14:43:30 -0700725 /*setupArpFlows();
726 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700727
pingping-lin1ada7ce2014-08-14 13:45:22 -0700728 setupBgpPaths();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700729
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700730 // Suppress link discovery on external-facing router ports
Ray Milkey269ffb92014-04-03 14:43:30 -0700731 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -0700732 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -0700733 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700734
Ray Milkey269ffb92014-04-03 14:43:30 -0700735 bgpUpdatesExecutor.execute(new Runnable() {
736 @Override
737 public void run() {
738 doUpdatesThread();
739 }
740 });
741 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700742
pingping-lin1ada7ce2014-08-14 13:45:22 -0700743 /**
744 * Thread for handling RIB updates.
745 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700746 private void doUpdatesThread() {
747 boolean interrupted = false;
748 try {
749 while (true) {
750 try {
751 RibUpdate update = ribUpdates.take();
752 switch (update.getOperation()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700753 case UPDATE:
754 if (validateUpdate(update)) {
755 processRibAdd(update);
756 } else {
757 log.debug("Rib UPDATE out of order: {} via {}",
758 update.getPrefix(), update.getRibEntry().getNextHop());
759 }
760 break;
761 case DELETE:
762 if (validateUpdate(update)) {
763 processRibDelete(update);
764 } else {
765 log.debug("Rib DELETE out of order: {} via {}",
766 update.getPrefix(), update.getRibEntry().getNextHop());
767 }
768 break;
769 default:
770 log.error("Unknown operation {}", update.getOperation());
771 break;
Ray Milkey269ffb92014-04-03 14:43:30 -0700772 }
773 } catch (InterruptedException e) {
774 log.debug("Interrupted while taking from updates queue", e);
775 interrupted = true;
776 } catch (Exception e) {
777 log.debug("exception", e);
778 }
779 }
780 } finally {
781 if (interrupted) {
782 Thread.currentThread().interrupt();
783 }
784 }
785 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700786
pingping-lin1ada7ce2014-08-14 13:45:22 -0700787 /**
788 * Judge whether a RIB update is in correct order.
789 *
790 * @param update RIB update
791 * @return boolean whether the RIB update is in in correct order
792 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700793 private boolean validateUpdate(RibUpdate update) {
794 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700795 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
796 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700797
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700798 // If there is no existing entry we must assume this is the most recent
799 // update. However this might not always be the case as we might have a
800 // POST then DELETE reordering.
801 // if (oldEntry == null ||
802 // !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700803 if (oldEntry == null) {
804 return true;
805 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700806
Ray Milkey269ffb92014-04-03 14:43:30 -0700807 // This handles the case where routes are gathered in the initial
808 // request because they don't have sequence number info
809 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
810 return true;
811 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700812
Ray Milkey269ffb92014-04-03 14:43:30 -0700813 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
814 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -0700815 }
Ray Milkey4985f212014-04-10 16:57:05 -0700816
817 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700818 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -0700819 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800820
pingping-lin1ada7ce2014-08-14 13:45:22 -0700821 /**
822 * To find the Interface which has longest matchable IP prefix (sub-network
823 * prefix) to next hop IP address.
824 *
825 * @param address the IP address of next hop router
826 * @return Interface the Interface which has longest matchable IP prefix
827 */
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700828 private Interface longestInterfacePrefixMatch(InetAddress address) {
829 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
830 Prefix.MAX_PREFIX_LENGTH);
831 Iterator<Interface> it =
832 interfaceRoutes.getValuesForKeysPrefixing(
833 prefixToSearchFor.toBinaryString()).iterator();
834 Interface intf = null;
835 // Find the last prefix, which will be the longest prefix
836 while (it.hasNext()) {
837 intf = it.next();
838 }
839
840 return intf;
841 }
842
Ray Milkey269ffb92014-04-03 14:43:30 -0700843 /*
844 * IConfigInfoService methods
845 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700846
Ray Milkey269ffb92014-04-03 14:43:30 -0700847 @Override
848 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700849 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -0700850 return (intf != null && intf.getIpAddress().equals(address));
851 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700852
Ray Milkey269ffb92014-04-03 14:43:30 -0700853 @Override
854 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700855 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -0700856 return (intf != null && !intf.getIpAddress().equals(address));
857 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700858
Ray Milkey269ffb92014-04-03 14:43:30 -0700859 @Override
860 public boolean fromExternalNetwork(long inDpid, short inPort) {
861 for (Interface intf : interfaces.values()) {
862 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
863 return true;
864 }
865 }
866 return false;
867 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700868
pingping-lin1ada7ce2014-08-14 13:45:22 -0700869 /**
870 * To find the relative egress Interface for a next hop IP address.
871 *
872 * @param dstIpAddress the IP address of next hop router
873 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700874 @Override
875 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700876 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700877 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700878
Ray Milkey269ffb92014-04-03 14:43:30 -0700879 @Override
880 public boolean hasLayer3Configuration() {
881 return !interfaces.isEmpty();
882 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700883
Ray Milkey269ffb92014-04-03 14:43:30 -0700884 @Override
885 public MACAddress getRouterMacAddress() {
886 return bgpdMacAddress;
887 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700888
Ray Milkey269ffb92014-04-03 14:43:30 -0700889 @Override
890 public short getVlan() {
891 return vlan;
892 }
pingping-lin1ada7ce2014-08-14 13:45:22 -0700893
pingping-lina2cbfad2013-03-07 08:39:21 +0800894}