blob: cd1c2de9649c60212e457a48ce3efc0268ad2ab8 [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);
pingping-linbec31fc2014-08-28 11:48:41 -0700205 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
206 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700207
pingping-lin1ada7ce2014-08-14 13:45:22 -0700208 intentIdGenerator = new IdBlockAllocatorBasedIntentIdGenerator(
209 controllerRegistryService);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700210
pingping-lin1ada7ce2014-08-14 13:45:22 -0700211 // TODO: initialize intentService
212
213 pushedRouteIntents = new ConcurrentHashMap<>();
214
Ray Milkey269ffb92014-04-03 14:43:30 -0700215 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
216 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700217
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700218 //flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700219
Ray Milkey269ffb92014-04-03 14:43:30 -0700220 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
221 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700222
Jonathan Hart938a0152014-04-07 18:27:31 -0700223 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700224 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
225 if (bgpdRestIp == null) {
226 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700227 throw new ConfigurationRuntimeException(
228 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700229 } else {
230 log.info("BgpdRestIp set to {}", bgpdRestIp);
231 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700232
Ray Milkey269ffb92014-04-03 14:43:30 -0700233 routerId = context.getConfigParams(this).get("RouterId");
234 if (routerId == null) {
235 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700236 throw new ConfigurationRuntimeException(
237 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700238 } else {
239 log.info("RouterId set to {}", routerId);
240 }
pingping-linba5c52f2014-02-11 16:52:01 -0800241
Ray Milkey269ffb92014-04-03 14:43:30 -0700242 String configFilenameParameter = context.getConfigParams(this).get("configfile");
243 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700244 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700245 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700246 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700247
Ray Milkey5df613b2014-04-15 10:50:56 -0700248 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700249 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700250
Ray Milkey269ffb92014-04-03 14:43:30 -0700251 @Override
252 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700253 restApi.addRestletRoutable(new SdnIpWebRoutable());
Komal Shah399a2922014-05-28 01:57:40 -0700254 restApi.addRestletRoutable(new SdnIpWebRoutableNew());
pingping-linba5c52f2014-02-11 16:52:01 -0800255
Jonathan Hart938a0152014-04-07 18:27:31 -0700256 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700257 retrieveRib();
258 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800259
Ray Milkey269ffb92014-04-03 14:43:30 -0700260 @Override
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700261 public RadixTree<RibEntry> getPtree() {
262 return bgpRoutes;
Ray Milkey269ffb92014-04-03 14:43:30 -0700263 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700264
Ray Milkey269ffb92014-04-03 14:43:30 -0700265 @Override
266 public void clearPtree() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700267 log.warn("Clear table operation not supported");
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
Jonathan Hart31e15f12014-04-10 10:33:00 -0700271 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700272 return bgpdRestIp;
273 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700274
Ray Milkey269ffb92014-04-03 14:43:30 -0700275 @Override
276 public String getRouterId() {
277 return routerId;
278 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700279
pingping-lin1ada7ce2014-08-14 13:45:22 -0700280 /**
281 * SDN-IP application will fetch all rib entries from BGPd when it starts.
282 * Especially when we restart SDN-IP application while the BGPd has been
283 * running all the time. Then before SDN-IP application re-connects to BGPd,
284 * there are already lots of rib entries in BGPd.
285 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700286 private void retrieveRib() {
287 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
288 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700289
Jonathan Hart938a0152014-04-07 18:27:31 -0700290 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700291 return;
292 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700293
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700294 try {
295 response = response.replaceAll("\"", "'");
296 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
297 JSONArray ribArray = jsonObj.getJSONArray("rib");
298 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700299
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700300 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700301
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700302 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700303
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700304 for (int j = 0; j < size; j++) {
305 JSONObject ribEntry = ribArray.getJSONObject(j);
306 String prefix = ribEntry.getString("prefix");
307 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700308
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700309 // Insert each rib entry into the local rib
310 String[] substring = prefix.split("/");
311 String prefix1 = substring[0];
312 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700313
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700314 Prefix p;
315 try {
316 p = new Prefix(prefix1, Integer.parseInt(mask1));
317 } catch (NumberFormatException e) {
318 log.warn("Wrong mask format in RIB JSON: {}", mask1);
319 continue;
320 } catch (IllegalArgumentException e1) {
321 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
322 continue;
323 }
324
325 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
326
327 try {
328 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
329 } catch (InterruptedException e) {
330 log.debug("Interrupted while pushing onto update queue");
331 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700332 }
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700333 } catch (JSONException e) {
334 // TODO don't parse JSON manually
335 log.error("Error parsing inital route table JSON:", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700336 }
337 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700338
pingping-lin1ada7ce2014-08-14 13:45:22 -0700339 /**
340 * Put RIB update to RIB update queue.
341 *
342 * @param update RIB update
343 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700344 @Override
345 public void newRibUpdate(RibUpdate update) {
346 try {
347 ribUpdates.put(update);
348 } catch (InterruptedException e) {
349 log.debug("Interrupted while putting on ribUpdates queue", e);
350 Thread.currentThread().interrupt();
351 }
352 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700353
pingping-lin1ada7ce2014-08-14 13:45:22 -0700354 /**
355 * Process adding RIB update.
356 * Put new RIB update into InvertedRadixTree. If there was an existing nexthop
357 * for this prefix, but the next hop was different, then execute deleting old
358 * RIB update. If the next hop is the SDN domain, we do not handle it at the
359 * moment. Otherwise, execute adding RIB.
360 *
361 * @param update RIB update
362 */
Jonathan Hart43f28742014-08-22 16:34:05 -0700363 protected void processRibAdd(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700364 synchronized (this) {
365 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700366
Jonathan Hart938a0152014-04-07 18:27:31 -0700367 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700368
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700369 RibEntry rib = bgpRoutes.put(prefix.toBinaryString(), update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700370
Jonathan Hart938a0152014-04-07 18:27:31 -0700371 if (rib != null && !rib.equals(update.getRibEntry())) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700372 // There was an existing nexthop for this prefix. This update
pingping-lin1ada7ce2014-08-14 13:45:22 -0700373 // supersedes that, so we need to remove the old flows for this
374 // prefix from the switches
375 executeDeleteRoute(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700376 }
Ray Milkey5d406012014-04-08 14:44:41 -0700377
Jonathan Hart938a0152014-04-07 18:27:31 -0700378 if (update.getRibEntry().getNextHop().equals(
379 InetAddresses.forString("0.0.0.0"))) {
380 // Route originated by SDN domain
381 // We don't handle these at the moment
382 log.debug("Own route {} to {}", prefix,
383 update.getRibEntry().getNextHop().getHostAddress());
384 return;
385 }
Ray Milkey5d406012014-04-08 14:44:41 -0700386
Ray Milkey7531a342014-04-11 15:08:12 -0700387 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700388 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700389 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700390
pingping-lin1ada7ce2014-08-14 13:45:22 -0700391 /**
392 * Execute adding RIB update.
393 * Find out the egress Interface and MAC address of next hop router for this
394 * RIB update. If the MAC address can not be found in ARP cache, then this
395 * prefix will be put in prefixesWaitingOnArp queue. Otherwise, new flow
396 * intent will be created and installed.
397 *
398 * @param update RIB update
399 */
Ray Milkey7531a342014-04-11 15:08:12 -0700400 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700401
Ray Milkey269ffb92014-04-03 14:43:30 -0700402 Prefix prefix = update.getPrefix();
403 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700404
pingping-lin1ada7ce2014-08-14 13:45:22 -0700405 InetAddress nextHopIpAddress = rib.getNextHop();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700406
Jonathan Hart43f28742014-08-22 16:34:05 -0700407 // See if we know the MAC address of the next hop
408 MACAddress nextHopMacAddress = proxyArp.getMacAddress(nextHopIpAddress);
pingping-lin1ada7ce2014-08-14 13:45:22 -0700409
Jonathan Hart43f28742014-08-22 16:34:05 -0700410 if (nextHopMacAddress == null) {
411 prefixesWaitingOnArp.put(nextHopIpAddress,
412 new RibUpdate(Operation.UPDATE, prefix, rib));
413 proxyArp.sendArpRequest(nextHopIpAddress, this, true);
414 return;
415 }
416
417 addRouteIntentToNextHop(prefix, nextHopIpAddress, nextHopMacAddress);
418 }
419
420 /**
421 * Adds a route intent given a prefix and a next hop IP address. This
422 * method will find the egress interface for the intent.
423 *
424 * @param prefix IP prefix of the route to add
425 * @param nextHopIpAddress IP address of the next hop
426 * @param nextHopMacAddress MAC address of the next hop
427 */
428 private void addRouteIntentToNextHop(Prefix prefix, InetAddress nextHopIpAddress,
429 MACAddress nextHopMacAddress) {
430
431 // Find the attachment point (egress interface) of the next hop
432 Interface egressInterface;
pingping-lin1ada7ce2014-08-14 13:45:22 -0700433 if (bgpPeers.containsKey(nextHopIpAddress)) {
434 // Route to a peer
435 log.debug("Route to peer {}", nextHopIpAddress);
436 BgpPeer peer = bgpPeers.get(nextHopIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700437 egressInterface = interfaces.get(peer.getInterfaceName());
438 } else {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700439 // Route to non-peer
440 log.debug("Route to non-peer {}", nextHopIpAddress);
441 egressInterface = getOutgoingInterface(nextHopIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700442 if (egressInterface == null) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700443 log.warn("No outgoing interface found for {}", nextHopIpAddress
444 .getHostAddress());
Ray Milkey269ffb92014-04-03 14:43:30 -0700445 return;
446 }
447 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700448
Jonathan Hart43f28742014-08-22 16:34:05 -0700449 doAddRouteIntent(prefix, egressInterface, nextHopMacAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700450 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700451
Ray Milkey269ffb92014-04-03 14:43:30 -0700452 /**
pingping-lin1ada7ce2014-08-14 13:45:22 -0700453 * Install a flow intent for a prefix.
454 * Intent will match dst IP prefix and rewrite dst MAC address at all other
455 * border switches, then forward packets according to dst MAC address.
456 *
457 * @param prefix IP prefix from BGP route
458 * @param egressInterface egress Interface connected to next hop router
459 * @param nextHopMacAddress MAC address of next hop router
Ray Milkey269ffb92014-04-03 14:43:30 -0700460 */
Jonathan Hart43f28742014-08-22 16:34:05 -0700461 private void doAddRouteIntent(Prefix prefix, Interface egressInterface,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700462 MACAddress nextHopMacAddress) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700463 log.debug("Adding intent for prefix {}, next hop mac {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700464 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700465
pingping-lin1ada7ce2014-08-14 13:45:22 -0700466 MultiPointToSinglePointIntent pushedIntent = pushedRouteIntents.get(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700467
pingping-lin1ada7ce2014-08-14 13:45:22 -0700468 // Just for testing.
469 if (pushedIntent != null) {
470 log.error("There should not be a pushed intent: {}", pushedIntent);
471 }
pingping-linba5c52f2014-02-11 16:52:01 -0800472
pingping-lin1ada7ce2014-08-14 13:45:22 -0700473 SwitchPort egressPort = egressInterface.getSwitchPort();
pingping-linba5c52f2014-02-11 16:52:01 -0800474
pingping-lin1ada7ce2014-08-14 13:45:22 -0700475 Set<SwitchPort> ingressPorts = new HashSet<SwitchPort>();
pingping-linba5c52f2014-02-11 16:52:01 -0800476
Ray Milkey269ffb92014-04-03 14:43:30 -0700477 for (Interface intf : interfaces.values()) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700478 if (!intf.equals(egressInterface)) {
479 SwitchPort srcPort = intf.getSwitchPort();
480 ingressPorts.add(srcPort);
Ray Milkey269ffb92014-04-03 14:43:30 -0700481 }
482 }
pingping-linba5c52f2014-02-11 16:52:01 -0800483
pingping-lin1ada7ce2014-08-14 13:45:22 -0700484 // Match the destination IP prefix at the first hop
485 PacketMatchBuilder builder = new PacketMatchBuilder();
486 builder.setDstIp(new IPv4(InetAddresses
487 .coerceToInteger(prefix.getInetAddress())),
488 (short) prefix.getPrefixLength());
489 PacketMatch packetMatch = builder.build();
pingping-linba5c52f2014-02-11 16:52:01 -0800490
pingping-lin1ada7ce2014-08-14 13:45:22 -0700491 // Rewrite the destination MAC address
492 ModifyDstMacAction modifyDstMacAction =
493 new ModifyDstMacAction(nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800494
pingping-lin1ada7ce2014-08-14 13:45:22 -0700495 MultiPointToSinglePointIntent intent =
496 new MultiPointToSinglePointIntent(intentIdGenerator.getNewId(),
497 packetMatch, modifyDstMacAction, ingressPorts, egressPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800498
pingping-lin1ada7ce2014-08-14 13:45:22 -0700499 intentService.submit(intent);
pingping-linba5c52f2014-02-11 16:52:01 -0800500
pingping-lin1ada7ce2014-08-14 13:45:22 -0700501 // Maintain the Intent
502 pushedRouteIntents.put(prefix, intent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700503 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700504
pingping-lin1ada7ce2014-08-14 13:45:22 -0700505 /**
506 * Remove prefix from InvertedRadixTree, if success, then try to delete the
507 * relative intent.
508 *
509 * @param update RIB update
510 */
Sho SHIMIZUba372192014-07-10 08:59:57 -0700511 private void processRibDelete(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700512 synchronized (this) {
513 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700514
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700515 // if (ptree.remove(prefix, update.getRibEntry())) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700516
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700517 // TODO check the change of logic here - remove doesn't check that
pingping-lin1ada7ce2014-08-14 13:45:22 -0700518 // the rib entry was what we expected (and we can't do this
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700519 // concurrently)
pingping-lin1ada7ce2014-08-14 13:45:22 -0700520
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700521 if (bgpRoutes.remove(prefix.toBinaryString())) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700522 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700523 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700524 * If no entry was removed, the <prefix, nexthop> wasn't there so
525 * it's probably already been removed and we don't need to do anything
526 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700527 executeDeleteRoute(prefix, update.getRibEntry());
528
Jonathan Hart938a0152014-04-07 18:27:31 -0700529 }
Jonathan Hart43f28742014-08-22 16:34:05 -0700530
531 prefixesWaitingOnArp.removeAll(prefix.getInetAddress());
532 // TODO cancel the request in the ARP manager as well
Ray Milkey269ffb92014-04-03 14:43:30 -0700533 }
534 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700535
Ray Milkey269ffb92014-04-03 14:43:30 -0700536 /**
pingping-lin1ada7ce2014-08-14 13:45:22 -0700537 * Delete prefix intent installed.
538 *
539 * @param prefix IP prefix withdrew in a rib update announcement
540 * @param ribEntry next hop information
Ray Milkey269ffb92014-04-03 14:43:30 -0700541 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700542 private void executeDeleteRoute(Prefix prefix, RibEntry ribEntry) {
543 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700544
pingping-lin1ada7ce2014-08-14 13:45:22 -0700545 MultiPointToSinglePointIntent intent = pushedRouteIntents.remove(prefix);
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700546
pingping-lin1ada7ce2014-08-14 13:45:22 -0700547 if (intent == null) {
548 log.debug("There is no intent in pushedRouteIntents to delete for " +
549 "prefix: {}", prefix);
550 } else {
551 intentService.withdraw(intent);
552 log.debug("Deleted the pushedRouteIntent for prefix: {}", prefix);
Ray Milkey269ffb92014-04-03 14:43:30 -0700553 }
Komal Shah399a2922014-05-28 01:57:40 -0700554 }
555
Ray Milkey269ffb92014-04-03 14:43:30 -0700556 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700557 * Setup the Paths to the BGP Daemon. Run a loop for all of the bgpPeers
558 * Push flow from BGPd to the peer Push flow from peer to BGPd Parameters to
559 * pass to the intent are as follows: String id, long srcSwitch, long
560 * srcPort, long srcMac, int srcIP, long dstSwitch, long dstPort, long
561 * dstMac, int dstIP
Komal Shah399a2922014-05-28 01:57:40 -0700562 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700563 private void setupBgpPaths() {
Komal Shah399a2922014-05-28 01:57:40 -0700564 IntentOperationList operations = new IntentOperationList();
565 for (BgpPeer bgpPeer : bgpPeers.values()) {
566 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700567 // Inet4Address.
Komal Shah399a2922014-05-28 01:57:40 -0700568 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
569 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700570 String fwdIntentId = caller + ":"
571 + controllerRegistryService.getNextUniqueId();
572 String bwdIntentId = caller + ":"
573 + controllerRegistryService.getNextUniqueId();
Komal Shah399a2922014-05-28 01:57:40 -0700574 SwitchPort srcPort =
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700575 new SwitchPort(bgpdAttachmentPoint.getDpid(),
576 bgpdAttachmentPoint.getPortNumber());
pingping-lin1ada7ce2014-08-14 13:45:22 -0700577 // TODO: replace the code below with peerInterface.getSwitchPort()
578 // when using poingToPointIntent
Komal Shah399a2922014-05-28 01:57:40 -0700579 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700580 new SwitchPort(new Dpid(peerInterface.getDpid()),
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700581 new PortNumber(peerInterface.getSwitchPort().getPortNumber()));
pingping-lin1ada7ce2014-08-14 13:45:22 -0700582
583 // TODO: add TCP port number 179 into intent for BGP
584
Komal Shah399a2922014-05-28 01:57:40 -0700585 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700586 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700587 ShortestPathIntent.EMPTYMACADDRESS, srcIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700588 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700589 ShortestPathIntent.EMPTYMACADDRESS, dstIP);
Komal Shah399a2922014-05-28 01:57:40 -0700590 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700591 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700592 ShortestPathIntent.EMPTYMACADDRESS, dstIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700593 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700594 ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700595 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
596 operations.add(operator, fwdIntent);
597 operations.add(operator, bwdIntent);
598 }
599 pathRuntime.executeIntentOperations(operations);
600 }
601
pingping-lin1ada7ce2014-08-14 13:45:22 -0700602 /**
603 * This method handles the prefixes which are waiting for ARP replies for
604 * MAC addresses of next hops.
605 *
606 * @param ipAddress next hop router IP address, for which we sent ARP request out
607 * @param macAddress MAC address which is relative to the ipAddress
608 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700609 @Override
610 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
611 log.debug("Received ARP response: {} => {}",
612 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700613
Ray Milkey269ffb92014-04-03 14:43:30 -0700614 /*
pingping-lin1ada7ce2014-08-14 13:45:22 -0700615 * We synchronize on this to prevent changes to the InvertedRadixTree
616 * while we're pushing intent. If the InvertedRadixTree changes, the
617 * InvertedRadixTree and intent could get out of sync.
Ray Milkey269ffb92014-04-03 14:43:30 -0700618 */
619 synchronized (this) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700620
pingping-lin1ada7ce2014-08-14 13:45:22 -0700621 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700622
Ray Milkey269ffb92014-04-03 14:43:30 -0700623 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700624 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700625
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700626 RibEntry rib = bgpRoutes.getValueForExactKey(
627 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700628 if (rib != null && rib.equals(update.getRibEntry())) {
629 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
630 rib.getNextHop().getHostAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700631 // We only push prefix flows if the prefix is still in the
pingping-lin1ada7ce2014-08-14 13:45:22 -0700632 // InvertedRadixTree and the next hop is the same as our update.
633 // The prefix could have been removed while we were waiting
634 // for the ARP, or the next hop could have changed.
Jonathan Hart43f28742014-08-22 16:34:05 -0700635 addRouteIntentToNextHop(update.getPrefix(), ipAddress,
636 macAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700637 } else {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700638 log.debug("Received ARP response, but {},{} is no longer in " +
639 "InvertedRadixTree", update.getPrefix(),
640 update.getRibEntry());
Ray Milkey269ffb92014-04-03 14:43:30 -0700641 }
642 }
643 }
644 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700645
pingping-lin1ada7ce2014-08-14 13:45:22 -0700646
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700647 /*private void setupArpFlows() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700648 OFMatch match = new OFMatch();
649 match.setDataLayerType(Ethernet.TYPE_ARP);
650 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700651
Ray Milkey269ffb92014-04-03 14:43:30 -0700652 OFFlowMod fm = new OFFlowMod();
653 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700654
Ray Milkey269ffb92014-04-03 14:43:30 -0700655 OFActionOutput action = new OFActionOutput();
656 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
657 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700658 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700659 actions.add(action);
660 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700661
Ray Milkey269ffb92014-04-03 14:43:30 -0700662 fm.setIdleTimeout((short) 0)
663 .setHardTimeout((short) 0)
664 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
665 .setCookie(0)
666 .setCommand(OFFlowMod.OFPFC_ADD)
667 .setPriority(ARP_PRIORITY)
668 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700669
Ray Milkey269ffb92014-04-03 14:43:30 -0700670 for (String strdpid : switches) {
671 flowCache.write(HexString.toLong(strdpid), fm);
672 }
673 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700674
Ray Milkey269ffb92014-04-03 14:43:30 -0700675 private void setupDefaultDropFlows() {
676 OFFlowMod fm = new OFFlowMod();
677 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -0700678 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700679
Ray Milkey269ffb92014-04-03 14:43:30 -0700680 fm.setIdleTimeout((short) 0)
681 .setHardTimeout((short) 0)
682 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
683 .setCookie(0)
684 .setCommand(OFFlowMod.OFPFC_ADD)
685 .setPriority((short) 0)
686 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700687
Ray Milkey269ffb92014-04-03 14:43:30 -0700688 OFFlowMod fmLLDP;
689 OFFlowMod fmBDDP;
690 try {
691 fmLLDP = fm.clone();
692 fmBDDP = fm.clone();
693 } catch (CloneNotSupportedException e1) {
694 log.error("Error cloning flow mod", e1);
695 return;
696 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700697
Ray Milkey269ffb92014-04-03 14:43:30 -0700698 OFMatch matchLLDP = new OFMatch();
699 matchLLDP.setDataLayerType((short) 0x88cc);
700 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
701 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700702
Ray Milkey269ffb92014-04-03 14:43:30 -0700703 OFMatch matchBDDP = new OFMatch();
704 matchBDDP.setDataLayerType((short) 0x8942);
705 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
706 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700707
Ray Milkey269ffb92014-04-03 14:43:30 -0700708 OFActionOutput action = new OFActionOutput();
709 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
710 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700711 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700712 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700713
Ray Milkey269ffb92014-04-03 14:43:30 -0700714 fmLLDP.setActions(actions);
715 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700716
Ray Milkey269ffb92014-04-03 14:43:30 -0700717 fmLLDP.setPriority(ARP_PRIORITY);
718 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
719 fmBDDP.setPriority(ARP_PRIORITY);
720 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700721
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700722 List<OFFlowMod> flowModList = new ArrayList<>(3);
Ray Milkey269ffb92014-04-03 14:43:30 -0700723 flowModList.add(fm);
724 flowModList.add(fmLLDP);
725 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700726
Ray Milkey269ffb92014-04-03 14:43:30 -0700727 for (String strdpid : switches) {
728 flowCache.write(HexString.toLong(strdpid), flowModList);
729 }
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700730 }*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700731
pingping-lin1ada7ce2014-08-14 13:45:22 -0700732 /**
733 * The SDN-IP application is started from this method.
734 */
735 @Override
736 public void beginRouting() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700737 log.debug("Topology is now ready, beginning routing function");
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700738
pingping-lin1ada7ce2014-08-14 13:45:22 -0700739 // TODO
Ray Milkey269ffb92014-04-03 14:43:30 -0700740 /*setupArpFlows();
741 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700742
pingping-lin1ada7ce2014-08-14 13:45:22 -0700743 setupBgpPaths();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700744
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700745 // Suppress link discovery on external-facing router ports
Ray Milkey269ffb92014-04-03 14:43:30 -0700746 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -0700747 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -0700748 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700749
Ray Milkey269ffb92014-04-03 14:43:30 -0700750 bgpUpdatesExecutor.execute(new Runnable() {
751 @Override
752 public void run() {
753 doUpdatesThread();
754 }
755 });
756 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700757
pingping-lin1ada7ce2014-08-14 13:45:22 -0700758 /**
759 * Thread for handling RIB updates.
760 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700761 private void doUpdatesThread() {
762 boolean interrupted = false;
763 try {
764 while (true) {
765 try {
766 RibUpdate update = ribUpdates.take();
767 switch (update.getOperation()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700768 case UPDATE:
769 if (validateUpdate(update)) {
770 processRibAdd(update);
771 } else {
772 log.debug("Rib UPDATE out of order: {} via {}",
773 update.getPrefix(), update.getRibEntry().getNextHop());
774 }
775 break;
776 case DELETE:
777 if (validateUpdate(update)) {
778 processRibDelete(update);
779 } else {
780 log.debug("Rib DELETE out of order: {} via {}",
781 update.getPrefix(), update.getRibEntry().getNextHop());
782 }
783 break;
784 default:
785 log.error("Unknown operation {}", update.getOperation());
786 break;
Ray Milkey269ffb92014-04-03 14:43:30 -0700787 }
788 } catch (InterruptedException e) {
789 log.debug("Interrupted while taking from updates queue", e);
790 interrupted = true;
791 } catch (Exception e) {
792 log.debug("exception", e);
793 }
794 }
795 } finally {
796 if (interrupted) {
797 Thread.currentThread().interrupt();
798 }
799 }
800 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700801
pingping-lin1ada7ce2014-08-14 13:45:22 -0700802 /**
803 * Judge whether a RIB update is in correct order.
804 *
805 * @param update RIB update
806 * @return boolean whether the RIB update is in in correct order
807 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700808 private boolean validateUpdate(RibUpdate update) {
809 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700810 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
811 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700812
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700813 // If there is no existing entry we must assume this is the most recent
814 // update. However this might not always be the case as we might have a
815 // POST then DELETE reordering.
816 // if (oldEntry == null ||
817 // !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700818 if (oldEntry == null) {
819 return true;
820 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700821
Ray Milkey269ffb92014-04-03 14:43:30 -0700822 // This handles the case where routes are gathered in the initial
823 // request because they don't have sequence number info
824 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
825 return true;
826 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700827
Ray Milkey269ffb92014-04-03 14:43:30 -0700828 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
829 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -0700830 }
Ray Milkey4985f212014-04-10 16:57:05 -0700831
832 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700833 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -0700834 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800835
pingping-lin1ada7ce2014-08-14 13:45:22 -0700836 /**
837 * To find the Interface which has longest matchable IP prefix (sub-network
838 * prefix) to next hop IP address.
839 *
840 * @param address the IP address of next hop router
841 * @return Interface the Interface which has longest matchable IP prefix
842 */
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700843 private Interface longestInterfacePrefixMatch(InetAddress address) {
844 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
845 Prefix.MAX_PREFIX_LENGTH);
846 Iterator<Interface> it =
847 interfaceRoutes.getValuesForKeysPrefixing(
848 prefixToSearchFor.toBinaryString()).iterator();
849 Interface intf = null;
850 // Find the last prefix, which will be the longest prefix
851 while (it.hasNext()) {
852 intf = it.next();
853 }
854
855 return intf;
856 }
857
Ray Milkey269ffb92014-04-03 14:43:30 -0700858 /*
859 * IConfigInfoService methods
860 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700861
Ray Milkey269ffb92014-04-03 14:43:30 -0700862 @Override
863 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700864 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -0700865 return (intf != null && intf.getIpAddress().equals(address));
866 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700867
Ray Milkey269ffb92014-04-03 14:43:30 -0700868 @Override
869 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700870 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -0700871 return (intf != null && !intf.getIpAddress().equals(address));
872 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700873
Ray Milkey269ffb92014-04-03 14:43:30 -0700874 @Override
875 public boolean fromExternalNetwork(long inDpid, short inPort) {
876 for (Interface intf : interfaces.values()) {
877 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
878 return true;
879 }
880 }
881 return false;
882 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700883
pingping-lin1ada7ce2014-08-14 13:45:22 -0700884 /**
885 * To find the relative egress Interface for a next hop IP address.
886 *
887 * @param dstIpAddress the IP address of next hop router
888 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700889 @Override
890 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700891 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700892 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700893
Ray Milkey269ffb92014-04-03 14:43:30 -0700894 @Override
895 public boolean hasLayer3Configuration() {
896 return !interfaces.isEmpty();
897 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700898
Ray Milkey269ffb92014-04-03 14:43:30 -0700899 @Override
900 public MACAddress getRouterMacAddress() {
901 return bgpdMacAddress;
902 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700903
Ray Milkey269ffb92014-04-03 14:43:30 -0700904 @Override
905 public short getVlan() {
906 return vlan;
907 }
pingping-lin1ada7ce2014-08-14 13:45:22 -0700908
pingping-lina2cbfad2013-03-07 08:39:21 +0800909}