blob: 5810d25155207f5e6a6b35c97b30a4df9d887a76 [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 */
Sho SHIMIZUba372192014-07-10 08:59:57 -0700363 private 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
Ray Milkey269ffb92014-04-03 14:43:30 -0700407 // Find the attachment point (egress interface) of the next hop
408 Interface egressInterface = null;
pingping-lin1ada7ce2014-08-14 13:45:22 -0700409
410 if (bgpPeers.containsKey(nextHopIpAddress)) {
411 // Route to a peer
412 log.debug("Route to peer {}", nextHopIpAddress);
413 BgpPeer peer = bgpPeers.get(nextHopIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700414 egressInterface = interfaces.get(peer.getInterfaceName());
415 } else {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700416 // Route to non-peer
417 log.debug("Route to non-peer {}", nextHopIpAddress);
418 egressInterface = getOutgoingInterface(nextHopIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700419 if (egressInterface == null) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700420 log.warn("No outgoing interface found for {}", nextHopIpAddress
421 .getHostAddress());
Ray Milkey269ffb92014-04-03 14:43:30 -0700422 return;
423 }
424 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700425
pingping-lin1ada7ce2014-08-14 13:45:22 -0700426 // See if we know the MAC address of the next hop
427 MACAddress nextHopMacAddress = proxyArp.getMacAddress(nextHopIpAddress);
428
Ray Milkey269ffb92014-04-03 14:43:30 -0700429 if (nextHopMacAddress == null) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700430 prefixesWaitingOnArp.put(nextHopIpAddress,
Ray Milkey269ffb92014-04-03 14:43:30 -0700431 new RibUpdate(Operation.UPDATE, prefix, rib));
pingping-lin1ada7ce2014-08-14 13:45:22 -0700432 proxyArp.sendArpRequest(nextHopIpAddress, this, true);
Ray Milkey269ffb92014-04-03 14:43:30 -0700433 return;
434 } else {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700435
pingping-lin1ada7ce2014-08-14 13:45:22 -0700436 //For all prefixes we need to add a intent for each of them
437 addRouteIntent(prefix, egressInterface, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700438
Ray Milkey269ffb92014-04-03 14:43:30 -0700439 }
pingping-lin1ada7ce2014-08-14 13:45:22 -0700440
Ray Milkey269ffb92014-04-03 14:43:30 -0700441 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700442
Ray Milkey269ffb92014-04-03 14:43:30 -0700443 /**
pingping-lin1ada7ce2014-08-14 13:45:22 -0700444 * Install a flow intent for a prefix.
445 * Intent will match dst IP prefix and rewrite dst MAC address at all other
446 * border switches, then forward packets according to dst MAC address.
447 *
448 * @param prefix IP prefix from BGP route
449 * @param egressInterface egress Interface connected to next hop router
450 * @param nextHopMacAddress MAC address of next hop router
Ray Milkey269ffb92014-04-03 14:43:30 -0700451 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700452 private void addRouteIntent(Prefix prefix, Interface egressInterface,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700453 MACAddress nextHopMacAddress) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700454 log.debug("Adding intent for prefix {}, next hop mac {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700455 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700456
pingping-lin1ada7ce2014-08-14 13:45:22 -0700457 MultiPointToSinglePointIntent pushedIntent = pushedRouteIntents.get(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700458
pingping-lin1ada7ce2014-08-14 13:45:22 -0700459 // Just for testing.
460 if (pushedIntent != null) {
461 log.error("There should not be a pushed intent: {}", pushedIntent);
462 }
pingping-linba5c52f2014-02-11 16:52:01 -0800463
pingping-lin1ada7ce2014-08-14 13:45:22 -0700464 SwitchPort egressPort = egressInterface.getSwitchPort();
pingping-linba5c52f2014-02-11 16:52:01 -0800465
pingping-lin1ada7ce2014-08-14 13:45:22 -0700466 Set<SwitchPort> ingressPorts = new HashSet<SwitchPort>();
pingping-linba5c52f2014-02-11 16:52:01 -0800467
Ray Milkey269ffb92014-04-03 14:43:30 -0700468 for (Interface intf : interfaces.values()) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700469 if (!intf.equals(egressInterface)) {
470 SwitchPort srcPort = intf.getSwitchPort();
471 ingressPorts.add(srcPort);
Ray Milkey269ffb92014-04-03 14:43:30 -0700472 }
473 }
pingping-linba5c52f2014-02-11 16:52:01 -0800474
pingping-lin1ada7ce2014-08-14 13:45:22 -0700475 // Match the destination IP prefix at the first hop
476 PacketMatchBuilder builder = new PacketMatchBuilder();
477 builder.setDstIp(new IPv4(InetAddresses
478 .coerceToInteger(prefix.getInetAddress())),
479 (short) prefix.getPrefixLength());
480 PacketMatch packetMatch = builder.build();
pingping-linba5c52f2014-02-11 16:52:01 -0800481
pingping-lin1ada7ce2014-08-14 13:45:22 -0700482 // Rewrite the destination MAC address
483 ModifyDstMacAction modifyDstMacAction =
484 new ModifyDstMacAction(nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800485
pingping-lin1ada7ce2014-08-14 13:45:22 -0700486 MultiPointToSinglePointIntent intent =
487 new MultiPointToSinglePointIntent(intentIdGenerator.getNewId(),
488 packetMatch, modifyDstMacAction, ingressPorts, egressPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800489
pingping-lin1ada7ce2014-08-14 13:45:22 -0700490 intentService.submit(intent);
pingping-linba5c52f2014-02-11 16:52:01 -0800491
pingping-lin1ada7ce2014-08-14 13:45:22 -0700492 // Maintain the Intent
493 pushedRouteIntents.put(prefix, intent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700494 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700495
pingping-lin1ada7ce2014-08-14 13:45:22 -0700496 /**
497 * Remove prefix from InvertedRadixTree, if success, then try to delete the
498 * relative intent.
499 *
500 * @param update RIB update
501 */
Sho SHIMIZUba372192014-07-10 08:59:57 -0700502 private void processRibDelete(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700503 synchronized (this) {
504 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700505
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700506 // if (ptree.remove(prefix, update.getRibEntry())) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700507
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700508 // TODO check the change of logic here - remove doesn't check that
pingping-lin1ada7ce2014-08-14 13:45:22 -0700509 // the rib entry was what we expected (and we can't do this
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700510 // concurrently)
pingping-lin1ada7ce2014-08-14 13:45:22 -0700511
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700512 if (bgpRoutes.remove(prefix.toBinaryString())) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700513 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700514 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700515 * If no entry was removed, the <prefix, nexthop> wasn't there so
516 * it's probably already been removed and we don't need to do anything
517 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700518 executeDeleteRoute(prefix, update.getRibEntry());
519
Jonathan Hart938a0152014-04-07 18:27:31 -0700520 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700521 }
522 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700523
Ray Milkey269ffb92014-04-03 14:43:30 -0700524 /**
pingping-lin1ada7ce2014-08-14 13:45:22 -0700525 * Delete prefix intent installed.
526 *
527 * @param prefix IP prefix withdrew in a rib update announcement
528 * @param ribEntry next hop information
Ray Milkey269ffb92014-04-03 14:43:30 -0700529 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700530 private void executeDeleteRoute(Prefix prefix, RibEntry ribEntry) {
531 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700532
pingping-lin1ada7ce2014-08-14 13:45:22 -0700533 MultiPointToSinglePointIntent intent = pushedRouteIntents.remove(prefix);
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700534
pingping-lin1ada7ce2014-08-14 13:45:22 -0700535 if (intent == null) {
536 log.debug("There is no intent in pushedRouteIntents to delete for " +
537 "prefix: {}", prefix);
538 } else {
539 intentService.withdraw(intent);
540 log.debug("Deleted the pushedRouteIntent for prefix: {}", prefix);
Ray Milkey269ffb92014-04-03 14:43:30 -0700541 }
Komal Shah399a2922014-05-28 01:57:40 -0700542 }
543
Ray Milkey269ffb92014-04-03 14:43:30 -0700544 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700545 * Setup the Paths to the BGP Daemon. Run a loop for all of the bgpPeers
546 * Push flow from BGPd to the peer Push flow from peer to BGPd Parameters to
547 * pass to the intent are as follows: String id, long srcSwitch, long
548 * srcPort, long srcMac, int srcIP, long dstSwitch, long dstPort, long
549 * dstMac, int dstIP
Komal Shah399a2922014-05-28 01:57:40 -0700550 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700551 private void setupBgpPaths() {
Komal Shah399a2922014-05-28 01:57:40 -0700552 IntentOperationList operations = new IntentOperationList();
553 for (BgpPeer bgpPeer : bgpPeers.values()) {
554 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700555 // Inet4Address.
Komal Shah399a2922014-05-28 01:57:40 -0700556 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
557 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700558 String fwdIntentId = caller + ":"
559 + controllerRegistryService.getNextUniqueId();
560 String bwdIntentId = caller + ":"
561 + controllerRegistryService.getNextUniqueId();
Komal Shah399a2922014-05-28 01:57:40 -0700562 SwitchPort srcPort =
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700563 new SwitchPort(bgpdAttachmentPoint.getDpid(),
564 bgpdAttachmentPoint.getPortNumber());
pingping-lin1ada7ce2014-08-14 13:45:22 -0700565 // TODO: replace the code below with peerInterface.getSwitchPort()
566 // when using poingToPointIntent
Komal Shah399a2922014-05-28 01:57:40 -0700567 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700568 new SwitchPort(new Dpid(peerInterface.getDpid()),
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700569 new PortNumber(peerInterface.getSwitchPort().getPortNumber()));
pingping-lin1ada7ce2014-08-14 13:45:22 -0700570
571 // TODO: add TCP port number 179 into intent for BGP
572
Komal Shah399a2922014-05-28 01:57:40 -0700573 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700574 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700575 ShortestPathIntent.EMPTYMACADDRESS, srcIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700576 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700577 ShortestPathIntent.EMPTYMACADDRESS, dstIP);
Komal Shah399a2922014-05-28 01:57:40 -0700578 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700579 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700580 ShortestPathIntent.EMPTYMACADDRESS, dstIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700581 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700582 ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700583 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
584 operations.add(operator, fwdIntent);
585 operations.add(operator, bwdIntent);
586 }
587 pathRuntime.executeIntentOperations(operations);
588 }
589
pingping-lin1ada7ce2014-08-14 13:45:22 -0700590 /**
591 * This method handles the prefixes which are waiting for ARP replies for
592 * MAC addresses of next hops.
593 *
594 * @param ipAddress next hop router IP address, for which we sent ARP request out
595 * @param macAddress MAC address which is relative to the ipAddress
596 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700597 @Override
598 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
599 log.debug("Received ARP response: {} => {}",
600 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700601
Ray Milkey269ffb92014-04-03 14:43:30 -0700602 /*
pingping-lin1ada7ce2014-08-14 13:45:22 -0700603 * We synchronize on this to prevent changes to the InvertedRadixTree
604 * while we're pushing intent. If the InvertedRadixTree changes, the
605 * InvertedRadixTree and intent could get out of sync.
Ray Milkey269ffb92014-04-03 14:43:30 -0700606 */
607 synchronized (this) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700608
pingping-lin1ada7ce2014-08-14 13:45:22 -0700609 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700610
Ray Milkey269ffb92014-04-03 14:43:30 -0700611 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700612 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700613
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700614 RibEntry rib = bgpRoutes.getValueForExactKey(
615 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700616 if (rib != null && rib.equals(update.getRibEntry())) {
617 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
618 rib.getNextHop().getHostAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700619 // We only push prefix flows if the prefix is still in the
pingping-lin1ada7ce2014-08-14 13:45:22 -0700620 // InvertedRadixTree and the next hop is the same as our update.
621 // The prefix could have been removed while we were waiting
622 // for the ARP, or the next hop could have changed.
Ray Milkey7531a342014-04-11 15:08:12 -0700623 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700624 } else {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700625 log.debug("Received ARP response, but {},{} is no longer in " +
626 "InvertedRadixTree", update.getPrefix(),
627 update.getRibEntry());
Ray Milkey269ffb92014-04-03 14:43:30 -0700628 }
629 }
630 }
631 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700632
pingping-lin1ada7ce2014-08-14 13:45:22 -0700633
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700634 /*private void setupArpFlows() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700635 OFMatch match = new OFMatch();
636 match.setDataLayerType(Ethernet.TYPE_ARP);
637 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700638
Ray Milkey269ffb92014-04-03 14:43:30 -0700639 OFFlowMod fm = new OFFlowMod();
640 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700641
Ray Milkey269ffb92014-04-03 14:43:30 -0700642 OFActionOutput action = new OFActionOutput();
643 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
644 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700645 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700646 actions.add(action);
647 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700648
Ray Milkey269ffb92014-04-03 14:43:30 -0700649 fm.setIdleTimeout((short) 0)
650 .setHardTimeout((short) 0)
651 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
652 .setCookie(0)
653 .setCommand(OFFlowMod.OFPFC_ADD)
654 .setPriority(ARP_PRIORITY)
655 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700656
Ray Milkey269ffb92014-04-03 14:43:30 -0700657 for (String strdpid : switches) {
658 flowCache.write(HexString.toLong(strdpid), fm);
659 }
660 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700661
Ray Milkey269ffb92014-04-03 14:43:30 -0700662 private void setupDefaultDropFlows() {
663 OFFlowMod fm = new OFFlowMod();
664 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -0700665 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700666
Ray Milkey269ffb92014-04-03 14:43:30 -0700667 fm.setIdleTimeout((short) 0)
668 .setHardTimeout((short) 0)
669 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
670 .setCookie(0)
671 .setCommand(OFFlowMod.OFPFC_ADD)
672 .setPriority((short) 0)
673 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700674
Ray Milkey269ffb92014-04-03 14:43:30 -0700675 OFFlowMod fmLLDP;
676 OFFlowMod fmBDDP;
677 try {
678 fmLLDP = fm.clone();
679 fmBDDP = fm.clone();
680 } catch (CloneNotSupportedException e1) {
681 log.error("Error cloning flow mod", e1);
682 return;
683 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700684
Ray Milkey269ffb92014-04-03 14:43:30 -0700685 OFMatch matchLLDP = new OFMatch();
686 matchLLDP.setDataLayerType((short) 0x88cc);
687 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
688 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700689
Ray Milkey269ffb92014-04-03 14:43:30 -0700690 OFMatch matchBDDP = new OFMatch();
691 matchBDDP.setDataLayerType((short) 0x8942);
692 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
693 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700694
Ray Milkey269ffb92014-04-03 14:43:30 -0700695 OFActionOutput action = new OFActionOutput();
696 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
697 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700698 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700699 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700700
Ray Milkey269ffb92014-04-03 14:43:30 -0700701 fmLLDP.setActions(actions);
702 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700703
Ray Milkey269ffb92014-04-03 14:43:30 -0700704 fmLLDP.setPriority(ARP_PRIORITY);
705 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
706 fmBDDP.setPriority(ARP_PRIORITY);
707 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700708
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700709 List<OFFlowMod> flowModList = new ArrayList<>(3);
Ray Milkey269ffb92014-04-03 14:43:30 -0700710 flowModList.add(fm);
711 flowModList.add(fmLLDP);
712 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700713
Ray Milkey269ffb92014-04-03 14:43:30 -0700714 for (String strdpid : switches) {
715 flowCache.write(HexString.toLong(strdpid), flowModList);
716 }
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700717 }*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700718
pingping-lin1ada7ce2014-08-14 13:45:22 -0700719 /**
720 * The SDN-IP application is started from this method.
721 */
722 @Override
723 public void beginRouting() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700724 log.debug("Topology is now ready, beginning routing function");
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700725
pingping-lin1ada7ce2014-08-14 13:45:22 -0700726 // TODO
Ray Milkey269ffb92014-04-03 14:43:30 -0700727 /*setupArpFlows();
728 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700729
pingping-lin1ada7ce2014-08-14 13:45:22 -0700730 setupBgpPaths();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700731
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700732 // Suppress link discovery on external-facing router ports
Ray Milkey269ffb92014-04-03 14:43:30 -0700733 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -0700734 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -0700735 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700736
Ray Milkey269ffb92014-04-03 14:43:30 -0700737 bgpUpdatesExecutor.execute(new Runnable() {
738 @Override
739 public void run() {
740 doUpdatesThread();
741 }
742 });
743 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700744
pingping-lin1ada7ce2014-08-14 13:45:22 -0700745 /**
746 * Thread for handling RIB updates.
747 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700748 private void doUpdatesThread() {
749 boolean interrupted = false;
750 try {
751 while (true) {
752 try {
753 RibUpdate update = ribUpdates.take();
754 switch (update.getOperation()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700755 case UPDATE:
756 if (validateUpdate(update)) {
757 processRibAdd(update);
758 } else {
759 log.debug("Rib UPDATE out of order: {} via {}",
760 update.getPrefix(), update.getRibEntry().getNextHop());
761 }
762 break;
763 case DELETE:
764 if (validateUpdate(update)) {
765 processRibDelete(update);
766 } else {
767 log.debug("Rib DELETE out of order: {} via {}",
768 update.getPrefix(), update.getRibEntry().getNextHop());
769 }
770 break;
771 default:
772 log.error("Unknown operation {}", update.getOperation());
773 break;
Ray Milkey269ffb92014-04-03 14:43:30 -0700774 }
775 } catch (InterruptedException e) {
776 log.debug("Interrupted while taking from updates queue", e);
777 interrupted = true;
778 } catch (Exception e) {
779 log.debug("exception", e);
780 }
781 }
782 } finally {
783 if (interrupted) {
784 Thread.currentThread().interrupt();
785 }
786 }
787 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700788
pingping-lin1ada7ce2014-08-14 13:45:22 -0700789 /**
790 * Judge whether a RIB update is in correct order.
791 *
792 * @param update RIB update
793 * @return boolean whether the RIB update is in in correct order
794 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700795 private boolean validateUpdate(RibUpdate update) {
796 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700797 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
798 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700799
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700800 // If there is no existing entry we must assume this is the most recent
801 // update. However this might not always be the case as we might have a
802 // POST then DELETE reordering.
803 // if (oldEntry == null ||
804 // !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700805 if (oldEntry == null) {
806 return true;
807 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700808
Ray Milkey269ffb92014-04-03 14:43:30 -0700809 // This handles the case where routes are gathered in the initial
810 // request because they don't have sequence number info
811 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
812 return true;
813 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700814
Ray Milkey269ffb92014-04-03 14:43:30 -0700815 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
816 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -0700817 }
Ray Milkey4985f212014-04-10 16:57:05 -0700818
819 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700820 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -0700821 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800822
pingping-lin1ada7ce2014-08-14 13:45:22 -0700823 /**
824 * To find the Interface which has longest matchable IP prefix (sub-network
825 * prefix) to next hop IP address.
826 *
827 * @param address the IP address of next hop router
828 * @return Interface the Interface which has longest matchable IP prefix
829 */
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700830 private Interface longestInterfacePrefixMatch(InetAddress address) {
831 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
832 Prefix.MAX_PREFIX_LENGTH);
833 Iterator<Interface> it =
834 interfaceRoutes.getValuesForKeysPrefixing(
835 prefixToSearchFor.toBinaryString()).iterator();
836 Interface intf = null;
837 // Find the last prefix, which will be the longest prefix
838 while (it.hasNext()) {
839 intf = it.next();
840 }
841
842 return intf;
843 }
844
Ray Milkey269ffb92014-04-03 14:43:30 -0700845 /*
846 * IConfigInfoService methods
847 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700848
Ray Milkey269ffb92014-04-03 14:43:30 -0700849 @Override
850 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700851 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -0700852 return (intf != null && intf.getIpAddress().equals(address));
853 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700854
Ray Milkey269ffb92014-04-03 14:43:30 -0700855 @Override
856 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700857 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -0700858 return (intf != null && !intf.getIpAddress().equals(address));
859 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700860
Ray Milkey269ffb92014-04-03 14:43:30 -0700861 @Override
862 public boolean fromExternalNetwork(long inDpid, short inPort) {
863 for (Interface intf : interfaces.values()) {
864 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
865 return true;
866 }
867 }
868 return false;
869 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700870
pingping-lin1ada7ce2014-08-14 13:45:22 -0700871 /**
872 * To find the relative egress Interface for a next hop IP address.
873 *
874 * @param dstIpAddress the IP address of next hop router
875 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700876 @Override
877 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700878 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700879 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700880
Ray Milkey269ffb92014-04-03 14:43:30 -0700881 @Override
882 public boolean hasLayer3Configuration() {
883 return !interfaces.isEmpty();
884 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700885
Ray Milkey269ffb92014-04-03 14:43:30 -0700886 @Override
887 public MACAddress getRouterMacAddress() {
888 return bgpdMacAddress;
889 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700890
Ray Milkey269ffb92014-04-03 14:43:30 -0700891 @Override
892 public short getVlan() {
893 return vlan;
894 }
pingping-lin1ada7ce2014-08-14 13:45:22 -0700895
pingping-lina2cbfad2013-03-07 08:39:21 +0800896}