blob: dd0c072fdd35dd4048d1a8dd499448cd073d5f6a [file] [log] [blame]
Jonathan Hart8f6dc092014-04-18 15:56:43 -07001package net.onrc.onos.apps.sdnip;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
Jonathan Hartd1f23252013-06-13 15:17:05 +12003import java.io.File;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07004import java.io.IOException;
5import java.net.InetAddress;
pingping-lina2cbfad2013-03-07 08:39:21 +08006import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07007import java.util.Collection;
pingping-lin0426dee2014-08-27 15:03:17 -07008import java.util.Collections;
pingping-lina2cbfad2013-03-07 08:39:21 +08009import java.util.HashMap;
pingping-lin1ada7ce2014-08-14 13:45:22 -070010import java.util.HashSet;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070011import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070012import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070013import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120014import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120015import java.util.concurrent.BlockingQueue;
pingping-lin1ada7ce2014-08-14 13:45:22 -070016import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120017import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120018import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120019import java.util.concurrent.LinkedBlockingQueue;
pingping-lina2cbfad2013-03-07 08:39:21 +080020
21import net.floodlightcontroller.core.module.FloodlightModuleContext;
22import net.floodlightcontroller.core.module.FloodlightModuleException;
23import net.floodlightcontroller.core.module.IFloodlightModule;
24import net.floodlightcontroller.core.module.IFloodlightService;
pingping-lina2cbfad2013-03-07 08:39:21 +080025import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120026import net.floodlightcontroller.util.MACAddress;
pingping-lin1ada7ce2014-08-14 13:45:22 -070027import net.onrc.onos.api.newintent.IntentService;
28import net.onrc.onos.api.newintent.MultiPointToSinglePointIntent;
pingping-linaea385b2014-09-04 18:15:19 -070029import net.onrc.onos.api.newintent.PointToPointIntent;
Jonathan Hart0961fe82014-04-03 09:56:25 -070030import net.onrc.onos.apps.proxyarp.IArpRequester;
31import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart8f6dc092014-04-18 15:56:43 -070032import net.onrc.onos.apps.sdnip.RibUpdate.Operation;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070033import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutable;
Komal Shah399a2922014-05-28 01:57:40 -070034import net.onrc.onos.apps.sdnip.web.SdnIpWebRoutableNew;
35import net.onrc.onos.core.intent.IntentOperation;
36import net.onrc.onos.core.intent.IntentOperationList;
37import net.onrc.onos.core.intent.ShortestPathIntent;
38import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
Jonathan Harta99ec672014-04-03 11:30:34 -070039import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070040import net.onrc.onos.core.main.config.IConfigInfoService;
pingping-linaea385b2014-09-04 18:15:19 -070041import net.onrc.onos.core.matchaction.action.Actions;
pingping-lin1ada7ce2014-08-14 13:45:22 -070042import net.onrc.onos.core.matchaction.action.ModifyDstMacAction;
43import net.onrc.onos.core.matchaction.match.PacketMatch;
44import net.onrc.onos.core.matchaction.match.PacketMatchBuilder;
45import net.onrc.onos.core.newintent.IdBlockAllocatorBasedIntentIdGenerator;
pingping-linaea385b2014-09-04 18:15:19 -070046import net.onrc.onos.core.packet.Ethernet;
Komal Shah399a2922014-05-28 01:57:40 -070047import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart23701d12014-04-03 10:45:48 -070048import net.onrc.onos.core.util.Dpid;
pingping-lin1ada7ce2014-08-14 13:45:22 -070049import net.onrc.onos.core.util.IPv4;
Yuta HIGUCHIfb564502014-06-16 21:29:00 -070050import net.onrc.onos.core.util.PortNumber;
Jonathan Hart23701d12014-04-03 10:45:48 -070051import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080052import net.sf.json.JSONArray;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070053import net.sf.json.JSONException;
pingping-line2a09ca2013-03-23 09:33:58 +080054import net.sf.json.JSONObject;
55import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080056
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070057import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120058import org.codehaus.jackson.JsonParseException;
59import org.codehaus.jackson.map.JsonMappingException;
60import org.codehaus.jackson.map.ObjectMapper;
pingping-lina2cbfad2013-03-07 08:39:21 +080061import org.slf4j.Logger;
62import org.slf4j.LoggerFactory;
63
Jonathan Hart4dfc3652013-08-02 20:22:36 +120064import com.google.common.collect.HashMultimap;
65import com.google.common.collect.Multimaps;
66import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120067import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120068import com.google.common.util.concurrent.ThreadFactoryBuilder;
Jonathan Hartf6978ce2014-06-23 11:20:04 -070069import com.googlecode.concurrenttrees.radix.RadixTree;
70import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
71import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
72import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120073
pingping-lin1ada7ce2014-08-14 13:45:22 -070074/**
75 * This class sets up BGP paths, handles RIB updates and relative intents.
76 * TODO: Thread-safe.
77 */
Jonathan Hart8f6dc092014-04-18 15:56:43 -070078public class SdnIp implements IFloodlightModule, ISdnIpService,
pingping-lin1ada7ce2014-08-14 13:45:22 -070079 IArpRequester, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070080
Jonathan Hart8f6dc092014-04-18 15:56:43 -070081 private static final Logger log = LoggerFactory.getLogger(SdnIp.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080082
Ray Milkey269ffb92014-04-03 14:43:30 -070083 private ILinkDiscoveryService linkDiscoveryService;
84 private IRestApiService restApi;
85 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070086
Jonathan Hartf6978ce2014-06-23 11:20:04 -070087 private InvertedRadixTree<RibEntry> bgpRoutes;
88 private InvertedRadixTree<Interface> interfaceRoutes;
89
Ray Milkey269ffb92014-04-03 14:43:30 -070090 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070091
Ray Milkey269ffb92014-04-03 14:43:30 -070092 private String bgpdRestIp;
93 private String routerId;
Ray Milkey5df613b2014-04-15 10:50:56 -070094 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
95 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070096
Komal Shah399a2922014-05-28 01:57:40 -070097 /* ShortestPath Intent Variables */
Sho SHIMIZU9ec39822014-07-10 17:15:12 -070098 private final String caller = "SdnIp";
Komal Shah399a2922014-05-28 01:57:40 -070099 private IControllerRegistryService controllerRegistryService;
pingping-lin1ada7ce2014-08-14 13:45:22 -0700100 private IntentService intentService;
Komal Shah399a2922014-05-28 01:57:40 -0700101 private IPathCalcRuntimeService pathRuntime;
102 /* Shortest Intent Path Variables */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700103 private IdBlockAllocatorBasedIntentIdGenerator intentIdGenerator;
104 //private static final short ARP_PRIORITY = 20;
Komal Shah399a2922014-05-28 01:57:40 -0700105
pingping-linaea385b2014-09-04 18:15:19 -0700106 private static final short BGP_PORT = 179;
107 public static final byte PROTOCOL_ICMP = 0x1;
108 public static final byte PROTOCOL_TCP = 0x6;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700109
Jonathan Hart938a0152014-04-07 18:27:31 -0700110 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700111 private List<String> switches;
112 private Map<String, Interface> interfaces;
113 private Map<InetAddress, BgpPeer> bgpPeers;
114 private SwitchPort bgpdAttachmentPoint;
115 private MACAddress bgpdMacAddress;
116 private short vlan;
pingping-lin0426dee2014-08-27 15:03:17 -0700117 private Set<SwitchPort> externalNetworkSwitchPorts;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700118
Ray Milkey269ffb92014-04-03 14:43:30 -0700119 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700120
Ray Milkey269ffb92014-04-03 14:43:30 -0700121 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700122
pingping-lin1ada7ce2014-08-14 13:45:22 -0700123 private ConcurrentHashMap<Prefix, MultiPointToSinglePointIntent> pushedRouteIntents;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700124
pingping-lin1ada7ce2014-08-14 13:45:22 -0700125 /**
126 * SDN-IP application has a configuration file. This method is to read all
127 * the info from this file.
128 *
129 * @param configFilename the name of configuration file for SDN-IP application
130 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700131 private void readConfiguration(String configFilename) {
132 File gatewaysFile = new File(configFilename);
133 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700134
Ray Milkey269ffb92014-04-03 14:43:30 -0700135 try {
136 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700137
Ray Milkey269ffb92014-04-03 14:43:30 -0700138 switches = config.getSwitches();
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700139 interfaces = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700140 for (Interface intf : config.getInterfaces()) {
141 interfaces.put(intf.getName(), intf);
pingping-lin0426dee2014-08-27 15:03:17 -0700142 externalNetworkSwitchPorts.add(new SwitchPort(intf.getDpid(),
143 intf.getPort()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700144 }
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700145 bgpPeers = new HashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700146 for (BgpPeer peer : config.getPeers()) {
147 bgpPeers.put(peer.getIpAddress(), peer);
148 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700149
Ray Milkey269ffb92014-04-03 14:43:30 -0700150 bgpdAttachmentPoint = new SwitchPort(
151 new Dpid(config.getBgpdAttachmentDpid()),
Yuta HIGUCHIa507baf2014-08-22 13:42:40 -0700152 PortNumber.uint16(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700153
Ray Milkey269ffb92014-04-03 14:43:30 -0700154 bgpdMacAddress = config.getBgpdMacAddress();
155 vlan = config.getVlan();
Sho SHIMIZUdde5a0b2014-07-09 10:42:23 -0700156 } catch (JsonParseException | JsonMappingException e) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700157 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700158 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700159 } catch (IOException e) {
160 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700161 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700162 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700163
pingping-lin1ada7ce2014-08-14 13:45:22 -0700164 // Populate the interface InvertedRadixTree
Ray Milkey269ffb92014-04-03 14:43:30 -0700165 for (Interface intf : interfaces.values()) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700166 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
167 intf.getPrefixLength());
168 interfaceRoutes.put(prefix.toBinaryString(), intf);
Ray Milkey269ffb92014-04-03 14:43:30 -0700169 }
170 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700171
Ray Milkey269ffb92014-04-03 14:43:30 -0700172 @Override
173 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700174 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700175 l.add(ISdnIpService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700176 l.add(IConfigInfoService.class);
177 return l;
178 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700179
Ray Milkey269ffb92014-04-03 14:43:30 -0700180 @Override
181 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700182 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
Jonathan Hart8f6dc092014-04-18 15:56:43 -0700183 m.put(ISdnIpService.class, this);
Ray Milkey269ffb92014-04-03 14:43:30 -0700184 m.put(IConfigInfoService.class, this);
185 return m;
186 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800187
Ray Milkey269ffb92014-04-03 14:43:30 -0700188 @Override
189 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700190 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 l.add(IRestApiService.class);
Komal Shah399a2922014-05-28 01:57:40 -0700192 l.add(IControllerRegistryService.class);
193 l.add(IPathCalcRuntimeService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700194 return l;
195 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700196
Ray Milkey269ffb92014-04-03 14:43:30 -0700197 @Override
198 public void init(FloodlightModuleContext context)
199 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700200
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700201 bgpRoutes = new ConcurrentInvertedRadixTree<>(
202 new DefaultByteArrayNodeFactory());
203 interfaceRoutes = new ConcurrentInvertedRadixTree<>(
204 new DefaultByteArrayNodeFactory());
pingping-lin0426dee2014-08-27 15:03:17 -0700205 externalNetworkSwitchPorts = new HashSet<SwitchPort>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700206
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700207 ribUpdates = new LinkedBlockingQueue<>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700208
pingping-lin1ada7ce2014-08-14 13:45:22 -0700209 // Register REST handler.
Ray Milkey269ffb92014-04-03 14:43:30 -0700210 restApi = context.getServiceImpl(IRestApiService.class);
211 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800212
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700213 controllerRegistryService = context
214 .getServiceImpl(IControllerRegistryService.class);
pingping-linbec31fc2014-08-28 11:48:41 -0700215 pathRuntime = context.getServiceImpl(IPathCalcRuntimeService.class);
216 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hart284e70f2014-07-05 12:32:51 -0700217
pingping-lin1ada7ce2014-08-14 13:45:22 -0700218 intentIdGenerator = new IdBlockAllocatorBasedIntentIdGenerator(
219 controllerRegistryService);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700220
pingping-lin1ada7ce2014-08-14 13:45:22 -0700221 // TODO: initialize intentService
222
223 pushedRouteIntents = new ConcurrentHashMap<>();
224
Ray Milkey269ffb92014-04-03 14:43:30 -0700225 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
226 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700227
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700228 //flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700229
Ray Milkey269ffb92014-04-03 14:43:30 -0700230 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
231 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700232
Jonathan Hart938a0152014-04-07 18:27:31 -0700233 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700234 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
235 if (bgpdRestIp == null) {
236 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700237 throw new ConfigurationRuntimeException(
238 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700239 } else {
240 log.info("BgpdRestIp set to {}", bgpdRestIp);
241 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700242
Ray Milkey269ffb92014-04-03 14:43:30 -0700243 routerId = context.getConfigParams(this).get("RouterId");
244 if (routerId == null) {
245 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700246 throw new ConfigurationRuntimeException(
247 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700248 } else {
249 log.info("RouterId set to {}", routerId);
250 }
pingping-linba5c52f2014-02-11 16:52:01 -0800251
Ray Milkey269ffb92014-04-03 14:43:30 -0700252 String configFilenameParameter = context.getConfigParams(this).get("configfile");
253 if (configFilenameParameter != null) {
Ray Milkey5df613b2014-04-15 10:50:56 -0700254 currentConfigFilename = configFilenameParameter;
Ray Milkey269ffb92014-04-03 14:43:30 -0700255 }
Ray Milkey5df613b2014-04-15 10:50:56 -0700256 log.debug("Config file set to {}", currentConfigFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700257
Ray Milkey5df613b2014-04-15 10:50:56 -0700258 readConfiguration(currentConfigFilename);
Ray Milkey269ffb92014-04-03 14:43:30 -0700259 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700260
Ray Milkey269ffb92014-04-03 14:43:30 -0700261 @Override
262 public void startUp(FloodlightModuleContext context) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700263 restApi.addRestletRoutable(new SdnIpWebRoutable());
Komal Shah399a2922014-05-28 01:57:40 -0700264 restApi.addRestletRoutable(new SdnIpWebRoutableNew());
pingping-linba5c52f2014-02-11 16:52:01 -0800265
Jonathan Hart938a0152014-04-07 18:27:31 -0700266 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700267 retrieveRib();
268 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800269
Ray Milkey269ffb92014-04-03 14:43:30 -0700270 @Override
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700271 public RadixTree<RibEntry> getPtree() {
272 return bgpRoutes;
Ray Milkey269ffb92014-04-03 14:43:30 -0700273 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700274
Ray Milkey269ffb92014-04-03 14:43:30 -0700275 @Override
276 public void clearPtree() {
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700277 log.warn("Clear table operation not supported");
Ray Milkey269ffb92014-04-03 14:43:30 -0700278 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700279
Ray Milkey269ffb92014-04-03 14:43:30 -0700280 @Override
Jonathan Hart31e15f12014-04-10 10:33:00 -0700281 public String getBgpdRestIp() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700282 return bgpdRestIp;
283 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700284
Ray Milkey269ffb92014-04-03 14:43:30 -0700285 @Override
286 public String getRouterId() {
287 return routerId;
288 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700289
pingping-lin1ada7ce2014-08-14 13:45:22 -0700290 /**
291 * SDN-IP application will fetch all rib entries from BGPd when it starts.
292 * Especially when we restart SDN-IP application while the BGPd has been
293 * running all the time. Then before SDN-IP application re-connects to BGPd,
294 * there are already lots of rib entries in BGPd.
295 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700296 private void retrieveRib() {
297 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
298 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700299
Jonathan Hart938a0152014-04-07 18:27:31 -0700300 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700301 return;
302 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700303
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700304 try {
305 response = response.replaceAll("\"", "'");
306 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
307 JSONArray ribArray = jsonObj.getJSONArray("rib");
308 String inboundRouterId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700309
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700310 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700311
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700312 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700313
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700314 for (int j = 0; j < size; j++) {
315 JSONObject ribEntry = ribArray.getJSONObject(j);
316 String prefix = ribEntry.getString("prefix");
317 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700318
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700319 // Insert each rib entry into the local rib
320 String[] substring = prefix.split("/");
321 String prefix1 = substring[0];
322 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700323
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700324 Prefix p;
325 try {
326 p = new Prefix(prefix1, Integer.parseInt(mask1));
327 } catch (NumberFormatException e) {
328 log.warn("Wrong mask format in RIB JSON: {}", mask1);
329 continue;
330 } catch (IllegalArgumentException e1) {
331 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
332 continue;
333 }
334
335 RibEntry rib = new RibEntry(inboundRouterId, nexthop);
336
337 try {
338 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
339 } catch (InterruptedException e) {
340 log.debug("Interrupted while pushing onto update queue");
341 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700342 }
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700343 } catch (JSONException e) {
344 // TODO don't parse JSON manually
345 log.error("Error parsing inital route table JSON:", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700346 }
347 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700348
pingping-lin1ada7ce2014-08-14 13:45:22 -0700349 /**
350 * Put RIB update to RIB update queue.
351 *
352 * @param update RIB update
353 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700354 @Override
355 public void newRibUpdate(RibUpdate update) {
356 try {
357 ribUpdates.put(update);
358 } catch (InterruptedException e) {
359 log.debug("Interrupted while putting on ribUpdates queue", e);
360 Thread.currentThread().interrupt();
361 }
362 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700363
pingping-lin1ada7ce2014-08-14 13:45:22 -0700364 /**
365 * Process adding RIB update.
366 * Put new RIB update into InvertedRadixTree. If there was an existing nexthop
367 * for this prefix, but the next hop was different, then execute deleting old
368 * RIB update. If the next hop is the SDN domain, we do not handle it at the
369 * moment. Otherwise, execute adding RIB.
370 *
371 * @param update RIB update
372 */
Jonathan Hart43f28742014-08-22 16:34:05 -0700373 protected void processRibAdd(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700374 synchronized (this) {
375 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700376
Jonathan Hart938a0152014-04-07 18:27:31 -0700377 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700378
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700379 RibEntry rib = bgpRoutes.put(prefix.toBinaryString(), update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700380
Jonathan Hart938a0152014-04-07 18:27:31 -0700381 if (rib != null && !rib.equals(update.getRibEntry())) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700382 // There was an existing nexthop for this prefix. This update
pingping-lin1ada7ce2014-08-14 13:45:22 -0700383 // supersedes that, so we need to remove the old flows for this
384 // prefix from the switches
385 executeDeleteRoute(prefix, rib);
Jonathan Hart938a0152014-04-07 18:27:31 -0700386 }
Ray Milkey5d406012014-04-08 14:44:41 -0700387
Jonathan Hart938a0152014-04-07 18:27:31 -0700388 if (update.getRibEntry().getNextHop().equals(
389 InetAddresses.forString("0.0.0.0"))) {
390 // Route originated by SDN domain
391 // We don't handle these at the moment
392 log.debug("Own route {} to {}", prefix,
393 update.getRibEntry().getNextHop().getHostAddress());
394 return;
395 }
Ray Milkey5d406012014-04-08 14:44:41 -0700396
Ray Milkey7531a342014-04-11 15:08:12 -0700397 executeRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700398 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700399 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700400
pingping-lin1ada7ce2014-08-14 13:45:22 -0700401 /**
402 * Execute adding RIB update.
403 * Find out the egress Interface and MAC address of next hop router for this
404 * RIB update. If the MAC address can not be found in ARP cache, then this
405 * prefix will be put in prefixesWaitingOnArp queue. Otherwise, new flow
406 * intent will be created and installed.
407 *
408 * @param update RIB update
409 */
Ray Milkey7531a342014-04-11 15:08:12 -0700410 private void executeRibAdd(RibUpdate update) {
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700411
Ray Milkey269ffb92014-04-03 14:43:30 -0700412 Prefix prefix = update.getPrefix();
413 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700414
pingping-lin1ada7ce2014-08-14 13:45:22 -0700415 InetAddress nextHopIpAddress = rib.getNextHop();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700416
Jonathan Hart43f28742014-08-22 16:34:05 -0700417 // See if we know the MAC address of the next hop
418 MACAddress nextHopMacAddress = proxyArp.getMacAddress(nextHopIpAddress);
pingping-lin1ada7ce2014-08-14 13:45:22 -0700419
Jonathan Hart43f28742014-08-22 16:34:05 -0700420 if (nextHopMacAddress == null) {
421 prefixesWaitingOnArp.put(nextHopIpAddress,
422 new RibUpdate(Operation.UPDATE, prefix, rib));
423 proxyArp.sendArpRequest(nextHopIpAddress, this, true);
424 return;
425 }
426
427 addRouteIntentToNextHop(prefix, nextHopIpAddress, nextHopMacAddress);
428 }
429
430 /**
431 * Adds a route intent given a prefix and a next hop IP address. This
432 * method will find the egress interface for the intent.
433 *
434 * @param prefix IP prefix of the route to add
435 * @param nextHopIpAddress IP address of the next hop
436 * @param nextHopMacAddress MAC address of the next hop
437 */
438 private void addRouteIntentToNextHop(Prefix prefix, InetAddress nextHopIpAddress,
439 MACAddress nextHopMacAddress) {
440
441 // Find the attachment point (egress interface) of the next hop
442 Interface egressInterface;
pingping-lin1ada7ce2014-08-14 13:45:22 -0700443 if (bgpPeers.containsKey(nextHopIpAddress)) {
444 // Route to a peer
445 log.debug("Route to peer {}", nextHopIpAddress);
446 BgpPeer peer = bgpPeers.get(nextHopIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700447 egressInterface = interfaces.get(peer.getInterfaceName());
448 } else {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700449 // Route to non-peer
450 log.debug("Route to non-peer {}", nextHopIpAddress);
451 egressInterface = getOutgoingInterface(nextHopIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700452 if (egressInterface == null) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700453 log.warn("No outgoing interface found for {}", nextHopIpAddress
454 .getHostAddress());
Ray Milkey269ffb92014-04-03 14:43:30 -0700455 return;
456 }
457 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700458
Jonathan Hart43f28742014-08-22 16:34:05 -0700459 doAddRouteIntent(prefix, egressInterface, nextHopMacAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700460 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700461
Ray Milkey269ffb92014-04-03 14:43:30 -0700462 /**
pingping-lin1ada7ce2014-08-14 13:45:22 -0700463 * Install a flow intent for a prefix.
464 * Intent will match dst IP prefix and rewrite dst MAC address at all other
465 * border switches, then forward packets according to dst MAC address.
466 *
467 * @param prefix IP prefix from BGP route
468 * @param egressInterface egress Interface connected to next hop router
469 * @param nextHopMacAddress MAC address of next hop router
Ray Milkey269ffb92014-04-03 14:43:30 -0700470 */
Jonathan Hart43f28742014-08-22 16:34:05 -0700471 private void doAddRouteIntent(Prefix prefix, Interface egressInterface,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700472 MACAddress nextHopMacAddress) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700473 log.debug("Adding intent for prefix {}, next hop mac {}",
Ray Milkey269ffb92014-04-03 14:43:30 -0700474 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700475
pingping-lin1ada7ce2014-08-14 13:45:22 -0700476 MultiPointToSinglePointIntent pushedIntent = pushedRouteIntents.get(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700477
pingping-lin1ada7ce2014-08-14 13:45:22 -0700478 // Just for testing.
479 if (pushedIntent != null) {
480 log.error("There should not be a pushed intent: {}", pushedIntent);
481 }
pingping-linba5c52f2014-02-11 16:52:01 -0800482
pingping-lin1ada7ce2014-08-14 13:45:22 -0700483 SwitchPort egressPort = egressInterface.getSwitchPort();
pingping-linba5c52f2014-02-11 16:52:01 -0800484
pingping-lin1ada7ce2014-08-14 13:45:22 -0700485 Set<SwitchPort> ingressPorts = new HashSet<SwitchPort>();
pingping-linba5c52f2014-02-11 16:52:01 -0800486
Ray Milkey269ffb92014-04-03 14:43:30 -0700487 for (Interface intf : interfaces.values()) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700488 if (!intf.equals(egressInterface)) {
489 SwitchPort srcPort = intf.getSwitchPort();
490 ingressPorts.add(srcPort);
Ray Milkey269ffb92014-04-03 14:43:30 -0700491 }
492 }
pingping-linba5c52f2014-02-11 16:52:01 -0800493
pingping-lin1ada7ce2014-08-14 13:45:22 -0700494 // Match the destination IP prefix at the first hop
495 PacketMatchBuilder builder = new PacketMatchBuilder();
496 builder.setDstIp(new IPv4(InetAddresses
497 .coerceToInteger(prefix.getInetAddress())),
498 (short) prefix.getPrefixLength());
499 PacketMatch packetMatch = builder.build();
pingping-linba5c52f2014-02-11 16:52:01 -0800500
pingping-lin1ada7ce2014-08-14 13:45:22 -0700501 // Rewrite the destination MAC address
502 ModifyDstMacAction modifyDstMacAction =
503 new ModifyDstMacAction(nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800504
pingping-lin1ada7ce2014-08-14 13:45:22 -0700505 MultiPointToSinglePointIntent intent =
506 new MultiPointToSinglePointIntent(intentIdGenerator.getNewId(),
507 packetMatch, modifyDstMacAction, ingressPorts, egressPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800508
pingping-lin1ada7ce2014-08-14 13:45:22 -0700509 intentService.submit(intent);
pingping-linba5c52f2014-02-11 16:52:01 -0800510
pingping-lin1ada7ce2014-08-14 13:45:22 -0700511 // Maintain the Intent
512 pushedRouteIntents.put(prefix, intent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700513 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700514
pingping-lin1ada7ce2014-08-14 13:45:22 -0700515 /**
516 * Remove prefix from InvertedRadixTree, if success, then try to delete the
517 * relative intent.
518 *
519 * @param update RIB update
520 */
Jonathan Hart6e01c852014-08-21 18:53:46 -0700521 protected void processRibDelete(RibUpdate update) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700522 synchronized (this) {
523 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700524
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700525 // if (ptree.remove(prefix, update.getRibEntry())) {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700526
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700527 // TODO check the change of logic here - remove doesn't check that
pingping-lin1ada7ce2014-08-14 13:45:22 -0700528 // the rib entry was what we expected (and we can't do this
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700529 // concurrently)
pingping-lin1ada7ce2014-08-14 13:45:22 -0700530
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700531 if (bgpRoutes.remove(prefix.toBinaryString())) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700532 /*
Jonathan Hart5e54f2e2014-04-17 13:43:40 -0700533 * Only delete flows if an entry was actually removed from the tree.
Jonathan Hart938a0152014-04-07 18:27:31 -0700534 * If no entry was removed, the <prefix, nexthop> wasn't there so
535 * it's probably already been removed and we don't need to do anything
536 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700537 executeDeleteRoute(prefix, update.getRibEntry());
538
Jonathan Hart938a0152014-04-07 18:27:31 -0700539 }
Jonathan Hart43f28742014-08-22 16:34:05 -0700540
541 prefixesWaitingOnArp.removeAll(prefix.getInetAddress());
542 // TODO cancel the request in the ARP manager as well
Ray Milkey269ffb92014-04-03 14:43:30 -0700543 }
544 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700545
Ray Milkey269ffb92014-04-03 14:43:30 -0700546 /**
pingping-lin1ada7ce2014-08-14 13:45:22 -0700547 * Delete prefix intent installed.
548 *
549 * @param prefix IP prefix withdrew in a rib update announcement
550 * @param ribEntry next hop information
Ray Milkey269ffb92014-04-03 14:43:30 -0700551 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700552 private void executeDeleteRoute(Prefix prefix, RibEntry ribEntry) {
553 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700554
pingping-lin1ada7ce2014-08-14 13:45:22 -0700555 MultiPointToSinglePointIntent intent = pushedRouteIntents.remove(prefix);
Pavlin Radoslavov9fc535a2014-04-11 13:00:12 -0700556
pingping-lin1ada7ce2014-08-14 13:45:22 -0700557 if (intent == null) {
558 log.debug("There is no intent in pushedRouteIntents to delete for " +
559 "prefix: {}", prefix);
560 } else {
561 intentService.withdraw(intent);
562 log.debug("Deleted the pushedRouteIntent for prefix: {}", prefix);
Ray Milkey269ffb92014-04-03 14:43:30 -0700563 }
Komal Shah399a2922014-05-28 01:57:40 -0700564 }
565
Ray Milkey269ffb92014-04-03 14:43:30 -0700566 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700567 * Setup the Paths to the BGP Daemon. Run a loop for all of the bgpPeers
568 * Push flow from BGPd to the peer Push flow from peer to BGPd Parameters to
569 * pass to the intent are as follows: String id, long srcSwitch, long
570 * srcPort, long srcMac, int srcIP, long dstSwitch, long dstPort, long
571 * dstMac, int dstIP
Komal Shah399a2922014-05-28 01:57:40 -0700572 */
pingping-lin1ada7ce2014-08-14 13:45:22 -0700573 private void setupBgpPaths() {
Komal Shah399a2922014-05-28 01:57:40 -0700574 IntentOperationList operations = new IntentOperationList();
575 for (BgpPeer bgpPeer : bgpPeers.values()) {
576 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700577 // Inet4Address.
Komal Shah399a2922014-05-28 01:57:40 -0700578 int srcIP = InetAddresses.coerceToInteger(peerInterface.getIpAddress());
579 int dstIP = InetAddresses.coerceToInteger(bgpPeer.getIpAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700580 String fwdIntentId = caller + ":"
581 + controllerRegistryService.getNextUniqueId();
582 String bwdIntentId = caller + ":"
583 + controllerRegistryService.getNextUniqueId();
Komal Shah399a2922014-05-28 01:57:40 -0700584 SwitchPort srcPort =
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700585 new SwitchPort(bgpdAttachmentPoint.getDpid(),
586 bgpdAttachmentPoint.getPortNumber());
pingping-lin1ada7ce2014-08-14 13:45:22 -0700587 // TODO: replace the code below with peerInterface.getSwitchPort()
588 // when using poingToPointIntent
Komal Shah399a2922014-05-28 01:57:40 -0700589 SwitchPort dstPort =
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700590 new SwitchPort(new Dpid(peerInterface.getDpid()),
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700591 new PortNumber(peerInterface.getSwitchPort().getPortNumber()));
pingping-lin1ada7ce2014-08-14 13:45:22 -0700592
593 // TODO: add TCP port number 179 into intent for BGP
594
Komal Shah399a2922014-05-28 01:57:40 -0700595 ShortestPathIntent fwdIntent = new ShortestPathIntent(fwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700596 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700597 ShortestPathIntent.EMPTYMACADDRESS, srcIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700598 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700599 ShortestPathIntent.EMPTYMACADDRESS, dstIP);
Komal Shah399a2922014-05-28 01:57:40 -0700600 ShortestPathIntent bwdIntent = new ShortestPathIntent(bwdIntentId,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700601 dstPort.getDpid().value(), dstPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700602 ShortestPathIntent.EMPTYMACADDRESS, dstIP,
Pavlin Radoslavov3d322f42014-08-18 14:58:55 -0700603 srcPort.getDpid().value(), srcPort.getPortNumber().value(),
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700604 ShortestPathIntent.EMPTYMACADDRESS, srcIP);
Komal Shah399a2922014-05-28 01:57:40 -0700605 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
606 operations.add(operator, fwdIntent);
607 operations.add(operator, bwdIntent);
608 }
609 pathRuntime.executeIntentOperations(operations);
610 }
611
pingping-linaea385b2014-09-04 18:15:19 -0700612
613 /**
614 * Setup paths for BGP Daemon and its peers. Run a loop for all the bgpPeers.
615 * Push intent for path from BGPd to the peer. Push intent for path from peer
616 * to BGPd.
617 */
618 private void setupBgpPathsWithNewIntent() {
619 for (BgpPeer bgpPeer : bgpPeers.values()) {
620
621 log.debug("Start to set up BGP paths.");
622
623 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
624
625 IPv4 bgpdAddress = new IPv4(InetAddresses
626 .coerceToInteger(peerInterface.getIpAddress()));
627 IPv4 bgpdPeerAddress = new IPv4(InetAddresses
628 .coerceToInteger(bgpPeer.getIpAddress()));
629
630 SwitchPort bgpdSwitchPort = bgpdAttachmentPoint;
631 SwitchPort bgpdPeerSwitchPort = peerInterface.getSwitchPort();
632
633 // install intent for BGP path from BGPd to BGP peer matching
634 // destination TCP port 179
635
636 // TODO: The usage of PacketMatchBuilder will be improved, then we
637 // only need to new the PacketMatchBuilder once.
638 // By then, the code here will be improved accordingly.
639 PacketMatchBuilder builderMatchDstTcpPort = new PacketMatchBuilder();
640 builderMatchDstTcpPort.setEtherType(Ethernet.TYPE_IPV4);
641 builderMatchDstTcpPort.setIpProto(PROTOCOL_TCP);
642 builderMatchDstTcpPort.setSrcIp(bgpdAddress);
643 builderMatchDstTcpPort.setDstIp(bgpdPeerAddress);
644 builderMatchDstTcpPort.setDstTcpPort(BGP_PORT);
645
646 PacketMatch packetMatch = builderMatchDstTcpPort.build();
647
648 PointToPointIntent intentMatchDstTcpPort = new PointToPointIntent(
649 intentIdGenerator.getNewId(), packetMatch, Actions
650 .nullAction(), bgpdSwitchPort, bgpdPeerSwitchPort);
651 intentService.submit(intentMatchDstTcpPort);
652 log.debug("Submitted BGP path intent matching dst TCP port 179 "
653 + "from BGPd to peer {}: {}",
654 bgpdPeerAddress, intentMatchDstTcpPort);
655
656 // install intent for BGP path from BGPd to BGP peer matching
657 // source TCP port 179
658 PacketMatchBuilder builderMatchSrcTcpPort = new PacketMatchBuilder();
659 builderMatchSrcTcpPort.setEtherType(Ethernet.TYPE_IPV4);
660 builderMatchSrcTcpPort.setIpProto(PROTOCOL_TCP);
661 builderMatchSrcTcpPort.setSrcIp(bgpdAddress);
662 builderMatchSrcTcpPort.setDstIp(bgpdPeerAddress);
663 builderMatchSrcTcpPort.setSrcTcpPort(BGP_PORT);
664
665 packetMatch = builderMatchSrcTcpPort.build();
666
667 PointToPointIntent intentMatchSrcTcpPort = new PointToPointIntent(
668 intentIdGenerator.getNewId(), packetMatch, Actions
669 .nullAction(), bgpdSwitchPort, bgpdPeerSwitchPort);
670 intentService.submit(intentMatchSrcTcpPort);
671 log.debug("Submitted BGP path intent matching src TCP port 179"
672 + "from BGPd to peer {}: {}",
673 bgpdPeerAddress, intentMatchSrcTcpPort);
674
675 // install intent for reversed BGP path from BGP peer to BGPd
676 // matching destination TCP port 179
677 PacketMatchBuilder reversedBuilderMatchDstTcpPort = new PacketMatchBuilder();
678 reversedBuilderMatchDstTcpPort.setEtherType(Ethernet.TYPE_IPV4);
679 reversedBuilderMatchDstTcpPort.setIpProto(PROTOCOL_TCP);
680 reversedBuilderMatchDstTcpPort.setSrcIp(bgpdPeerAddress);
681 reversedBuilderMatchDstTcpPort.setDstIp(bgpdAddress);
682 reversedBuilderMatchDstTcpPort.setDstTcpPort(BGP_PORT);
683
684 packetMatch = reversedBuilderMatchDstTcpPort.build();
685
686 PointToPointIntent reversedIntentMatchDstTcpPort = new PointToPointIntent(
687 intentIdGenerator.getNewId(), packetMatch, Actions
688 .nullAction(), bgpdPeerSwitchPort, bgpdSwitchPort);
689 intentService.submit(reversedIntentMatchDstTcpPort);
690 log.debug("Submitted BGP path intent matching dst TCP port 179"
691 + "from BGP peer {} to BGPd: {}",
692 bgpdPeerAddress, reversedIntentMatchDstTcpPort);
693
694 // install intent for reversed BGP path from BGP peer to BGPd
695 // matching source TCP port 179
696 PacketMatchBuilder reversedBuilderMatchSrcTcpPort = new PacketMatchBuilder();
697 reversedBuilderMatchSrcTcpPort.setEtherType(Ethernet.TYPE_IPV4);
698 reversedBuilderMatchSrcTcpPort.setIpProto(PROTOCOL_TCP);
699 reversedBuilderMatchSrcTcpPort.setSrcIp(bgpdPeerAddress);
700 reversedBuilderMatchSrcTcpPort.setDstIp(bgpdAddress);
701 reversedBuilderMatchSrcTcpPort.setSrcTcpPort(BGP_PORT);
702
703 packetMatch = reversedBuilderMatchSrcTcpPort.build();
704
705 PointToPointIntent reversedIntentMatchSrcTcpPort = new PointToPointIntent(
706 intentIdGenerator.getNewId(), packetMatch, Actions
707 .nullAction(), bgpdPeerSwitchPort, bgpdSwitchPort);
708 intentService.submit(reversedIntentMatchSrcTcpPort);
709 log.debug("Submitted BGP path intent matching src TCP port 179"
710 + "from BGP peer {} to BGPd: {}",
711 bgpdPeerAddress, reversedIntentMatchSrcTcpPort);
712
713 }
714
715 }
716
717 /**
718 * Setup ICMP paths between BGP Daemon and its peers. Run a loop for all the
719 * bgpPeers. Push intent for path from BGPd to the peer. Push intent for path
720 * from peer to BGPd.
721 */
722 private void setupIcmpPaths() {
723 for (BgpPeer bgpPeer : bgpPeers.values()) {
724
725 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
726
727 PacketMatchBuilder builder = new PacketMatchBuilder();
728 builder.setEtherType(Ethernet.TYPE_IPV4);
729 builder.setIpProto(PROTOCOL_ICMP);
730
731 IPv4 bgpdAddress = new IPv4(InetAddresses
732 .coerceToInteger(peerInterface.getIpAddress()));
733 IPv4 bgpdPeerAddress = new IPv4(InetAddresses
734 .coerceToInteger(bgpPeer.getIpAddress()));
735
736 SwitchPort bgpdSwitchPort = bgpdAttachmentPoint;
737 SwitchPort bgpdPeerSwitchPort = peerInterface.getSwitchPort();
738
739 // install intent for ICMP path from BGPd to BGP peer
740 builder.setSrcIp(bgpdAddress);
741 builder.setDstIp(bgpdPeerAddress);
742 PacketMatch packetMatch = builder.build();
743
744 PointToPointIntent intent = new PointToPointIntent(
745 intentIdGenerator.getNewId(), packetMatch, Actions
746 .nullAction(), bgpdSwitchPort, bgpdPeerSwitchPort);
747 intentService.submit(intent);
748 log.debug("Submitted ICMP path intent from BGPd to peer {}: {}",
749 bgpdPeerAddress, intent);
750
751 // install intent for reversed ICMP path from BGP peer to BGPd
752 builder.setSrcIp(bgpdPeerAddress);
753 builder.setDstIp(bgpdAddress);
754 packetMatch = builder.build();
755
756 PointToPointIntent reversedIntent = new PointToPointIntent(
757 intentIdGenerator.getNewId(), packetMatch, Actions
758 .nullAction(), bgpdPeerSwitchPort, bgpdSwitchPort);
759 intentService.submit(reversedIntent);
760 log.debug("Submitted ICMP path intent from BGP peer {} to BGPd: {}",
761 bgpdPeerAddress, reversedIntent);
762 }
763
764 }
765
pingping-lin1ada7ce2014-08-14 13:45:22 -0700766 /**
767 * This method handles the prefixes which are waiting for ARP replies for
768 * MAC addresses of next hops.
769 *
770 * @param ipAddress next hop router IP address, for which we sent ARP request out
771 * @param macAddress MAC address which is relative to the ipAddress
772 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700773 @Override
774 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
775 log.debug("Received ARP response: {} => {}",
776 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700777
Ray Milkey269ffb92014-04-03 14:43:30 -0700778 /*
pingping-lin1ada7ce2014-08-14 13:45:22 -0700779 * We synchronize on this to prevent changes to the InvertedRadixTree
780 * while we're pushing intent. If the InvertedRadixTree changes, the
781 * InvertedRadixTree and intent could get out of sync.
Ray Milkey269ffb92014-04-03 14:43:30 -0700782 */
783 synchronized (this) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700784
pingping-lin1ada7ce2014-08-14 13:45:22 -0700785 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700786
Ray Milkey269ffb92014-04-03 14:43:30 -0700787 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700788 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700789
Jonathan Hartf6978ce2014-06-23 11:20:04 -0700790 RibEntry rib = bgpRoutes.getValueForExactKey(
791 update.getPrefix().toBinaryString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700792 if (rib != null && rib.equals(update.getRibEntry())) {
793 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
794 rib.getNextHop().getHostAddress());
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700795 // We only push prefix flows if the prefix is still in the
pingping-lin1ada7ce2014-08-14 13:45:22 -0700796 // InvertedRadixTree and the next hop is the same as our update.
797 // The prefix could have been removed while we were waiting
798 // for the ARP, or the next hop could have changed.
Jonathan Hart43f28742014-08-22 16:34:05 -0700799 addRouteIntentToNextHop(update.getPrefix(), ipAddress,
800 macAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -0700801 } else {
pingping-lin1ada7ce2014-08-14 13:45:22 -0700802 log.debug("Received ARP response, but {},{} is no longer in " +
803 "InvertedRadixTree", update.getPrefix(),
804 update.getRibEntry());
Ray Milkey269ffb92014-04-03 14:43:30 -0700805 }
806 }
807 }
808 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700809
pingping-lin1ada7ce2014-08-14 13:45:22 -0700810
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700811 /*private void setupArpFlows() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700812 OFMatch match = new OFMatch();
813 match.setDataLayerType(Ethernet.TYPE_ARP);
814 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700815
Ray Milkey269ffb92014-04-03 14:43:30 -0700816 OFFlowMod fm = new OFFlowMod();
817 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700818
Ray Milkey269ffb92014-04-03 14:43:30 -0700819 OFActionOutput action = new OFActionOutput();
820 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
821 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700822 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700823 actions.add(action);
824 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700825
Ray Milkey269ffb92014-04-03 14:43:30 -0700826 fm.setIdleTimeout((short) 0)
827 .setHardTimeout((short) 0)
828 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
829 .setCookie(0)
830 .setCommand(OFFlowMod.OFPFC_ADD)
831 .setPriority(ARP_PRIORITY)
832 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700833
Ray Milkey269ffb92014-04-03 14:43:30 -0700834 for (String strdpid : switches) {
835 flowCache.write(HexString.toLong(strdpid), fm);
836 }
837 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700838
Ray Milkey269ffb92014-04-03 14:43:30 -0700839 private void setupDefaultDropFlows() {
840 OFFlowMod fm = new OFFlowMod();
841 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -0700842 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700843
Ray Milkey269ffb92014-04-03 14:43:30 -0700844 fm.setIdleTimeout((short) 0)
845 .setHardTimeout((short) 0)
846 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
847 .setCookie(0)
848 .setCommand(OFFlowMod.OFPFC_ADD)
849 .setPriority((short) 0)
850 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700851
Ray Milkey269ffb92014-04-03 14:43:30 -0700852 OFFlowMod fmLLDP;
853 OFFlowMod fmBDDP;
854 try {
855 fmLLDP = fm.clone();
856 fmBDDP = fm.clone();
857 } catch (CloneNotSupportedException e1) {
858 log.error("Error cloning flow mod", e1);
859 return;
860 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700861
Ray Milkey269ffb92014-04-03 14:43:30 -0700862 OFMatch matchLLDP = new OFMatch();
863 matchLLDP.setDataLayerType((short) 0x88cc);
864 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
865 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700866
Ray Milkey269ffb92014-04-03 14:43:30 -0700867 OFMatch matchBDDP = new OFMatch();
868 matchBDDP.setDataLayerType((short) 0x8942);
869 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
870 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700871
Ray Milkey269ffb92014-04-03 14:43:30 -0700872 OFActionOutput action = new OFActionOutput();
873 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
874 action.setMaxLength((short) 0xffff);
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700875 List<OFAction> actions = new ArrayList<>(1);
Ray Milkey269ffb92014-04-03 14:43:30 -0700876 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700877
Ray Milkey269ffb92014-04-03 14:43:30 -0700878 fmLLDP.setActions(actions);
879 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700880
Ray Milkey269ffb92014-04-03 14:43:30 -0700881 fmLLDP.setPriority(ARP_PRIORITY);
882 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
883 fmBDDP.setPriority(ARP_PRIORITY);
884 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700885
Sho SHIMIZU84a72de2014-07-09 07:56:40 -0700886 List<OFFlowMod> flowModList = new ArrayList<>(3);
Ray Milkey269ffb92014-04-03 14:43:30 -0700887 flowModList.add(fm);
888 flowModList.add(fmLLDP);
889 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700890
Ray Milkey269ffb92014-04-03 14:43:30 -0700891 for (String strdpid : switches) {
892 flowCache.write(HexString.toLong(strdpid), flowModList);
893 }
Jonathan Hartc78b8f62014-08-07 22:31:09 -0700894 }*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700895
pingping-lin1ada7ce2014-08-14 13:45:22 -0700896 /**
897 * The SDN-IP application is started from this method.
898 */
899 @Override
900 public void beginRouting() {
Ray Milkey269ffb92014-04-03 14:43:30 -0700901 log.debug("Topology is now ready, beginning routing function");
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700902
pingping-lin1ada7ce2014-08-14 13:45:22 -0700903 // TODO
Ray Milkey269ffb92014-04-03 14:43:30 -0700904 /*setupArpFlows();
905 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700906
pingping-lin1ada7ce2014-08-14 13:45:22 -0700907 setupBgpPaths();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700908
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700909 // Suppress link discovery on external-facing router ports
Ray Milkey269ffb92014-04-03 14:43:30 -0700910 for (Interface intf : interfaces.values()) {
Jonathan Hart284e70f2014-07-05 12:32:51 -0700911 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
Ray Milkey269ffb92014-04-03 14:43:30 -0700912 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700913
Ray Milkey269ffb92014-04-03 14:43:30 -0700914 bgpUpdatesExecutor.execute(new Runnable() {
915 @Override
916 public void run() {
917 doUpdatesThread();
918 }
919 });
920 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700921
pingping-lin1ada7ce2014-08-14 13:45:22 -0700922 /**
pingping-linaea385b2014-09-04 18:15:19 -0700923 * The SDN-IP application is started from this method.
924 * Before intent framework is ready, we need two methods to start the
925 * application.
926 */
927 @Override
928 public void beginRoutingWithNewIntent() {
929 log.debug("Topology is now ready, beginning routing function");
930
931 // TODO
932 /*setupArpFlows();
933 setupDefaultDropFlows();*/
934
935 setupBgpPathsWithNewIntent();
936 setupIcmpPaths();
937
938 // Suppress link discovery on external-facing router ports
939 for (Interface intf : interfaces.values()) {
940 linkDiscoveryService.disableDiscoveryOnPort(intf.getDpid(), intf.getPort());
941 }
942
943 bgpUpdatesExecutor.execute(new Runnable() {
944 @Override
945 public void run() {
946 doUpdatesThread();
947 }
948 });
949 }
950
951 /**
pingping-lin1ada7ce2014-08-14 13:45:22 -0700952 * Thread for handling RIB updates.
953 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700954 private void doUpdatesThread() {
955 boolean interrupted = false;
956 try {
957 while (true) {
958 try {
959 RibUpdate update = ribUpdates.take();
960 switch (update.getOperation()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700961 case UPDATE:
962 if (validateUpdate(update)) {
963 processRibAdd(update);
964 } else {
965 log.debug("Rib UPDATE out of order: {} via {}",
966 update.getPrefix(), update.getRibEntry().getNextHop());
967 }
968 break;
969 case DELETE:
970 if (validateUpdate(update)) {
971 processRibDelete(update);
972 } else {
973 log.debug("Rib DELETE out of order: {} via {}",
974 update.getPrefix(), update.getRibEntry().getNextHop());
975 }
976 break;
977 default:
978 log.error("Unknown operation {}", update.getOperation());
979 break;
Ray Milkey269ffb92014-04-03 14:43:30 -0700980 }
981 } catch (InterruptedException e) {
982 log.debug("Interrupted while taking from updates queue", e);
983 interrupted = true;
984 } catch (Exception e) {
985 log.debug("exception", e);
986 }
987 }
988 } finally {
989 if (interrupted) {
990 Thread.currentThread().interrupt();
991 }
992 }
993 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700994
pingping-lin1ada7ce2014-08-14 13:45:22 -0700995 /**
996 * Judge whether a RIB update is in correct order.
997 *
998 * @param update RIB update
999 * @return boolean whether the RIB update is in in correct order
1000 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001001 private boolean validateUpdate(RibUpdate update) {
1002 RibEntry newEntry = update.getRibEntry();
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001003 RibEntry oldEntry = bgpRoutes.getValueForExactKey(
1004 update.getPrefix().toBinaryString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001005
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001006 // If there is no existing entry we must assume this is the most recent
1007 // update. However this might not always be the case as we might have a
1008 // POST then DELETE reordering.
1009 // if (oldEntry == null ||
1010 // !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
Ray Milkey269ffb92014-04-03 14:43:30 -07001011 if (oldEntry == null) {
1012 return true;
1013 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001014
Ray Milkey269ffb92014-04-03 14:43:30 -07001015 // This handles the case where routes are gathered in the initial
1016 // request because they don't have sequence number info
1017 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1018 return true;
1019 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001020
Ray Milkey269ffb92014-04-03 14:43:30 -07001021 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1022 return true;
Ray Milkey269ffb92014-04-03 14:43:30 -07001023 }
Ray Milkey4985f212014-04-10 16:57:05 -07001024
1025 return newEntry.getSysUpTime() == oldEntry.getSysUpTime() &&
Brian O'Connorc67f9fa2014-08-07 18:17:46 -07001026 newEntry.getSequenceNum() > oldEntry.getSequenceNum();
Ray Milkey269ffb92014-04-03 14:43:30 -07001027 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001028
pingping-lin1ada7ce2014-08-14 13:45:22 -07001029 /**
1030 * To find the Interface which has longest matchable IP prefix (sub-network
1031 * prefix) to next hop IP address.
1032 *
1033 * @param address the IP address of next hop router
1034 * @return Interface the Interface which has longest matchable IP prefix
1035 */
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001036 private Interface longestInterfacePrefixMatch(InetAddress address) {
1037 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
1038 Prefix.MAX_PREFIX_LENGTH);
1039 Iterator<Interface> it =
1040 interfaceRoutes.getValuesForKeysPrefixing(
1041 prefixToSearchFor.toBinaryString()).iterator();
1042 Interface intf = null;
1043 // Find the last prefix, which will be the longest prefix
1044 while (it.hasNext()) {
1045 intf = it.next();
1046 }
1047
1048 return intf;
1049 }
1050
Ray Milkey269ffb92014-04-03 14:43:30 -07001051 /*
1052 * IConfigInfoService methods
1053 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001054
Ray Milkey269ffb92014-04-03 14:43:30 -07001055 @Override
1056 public boolean isInterfaceAddress(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001057 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001058 return (intf != null && intf.getIpAddress().equals(address));
1059 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001060
Ray Milkey269ffb92014-04-03 14:43:30 -07001061 @Override
1062 public boolean inConnectedNetwork(InetAddress address) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001063 Interface intf = longestInterfacePrefixMatch(address);
Ray Milkey269ffb92014-04-03 14:43:30 -07001064 return (intf != null && !intf.getIpAddress().equals(address));
1065 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001066
Ray Milkey269ffb92014-04-03 14:43:30 -07001067 @Override
1068 public boolean fromExternalNetwork(long inDpid, short inPort) {
1069 for (Interface intf : interfaces.values()) {
1070 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1071 return true;
1072 }
1073 }
1074 return false;
1075 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001076
pingping-lin1ada7ce2014-08-14 13:45:22 -07001077 /**
1078 * To find the relative egress Interface for a next hop IP address.
1079 *
1080 * @param dstIpAddress the IP address of next hop router
1081 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001082 @Override
1083 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
Jonathan Hartf6978ce2014-06-23 11:20:04 -07001084 return longestInterfacePrefixMatch(dstIpAddress);
Ray Milkey269ffb92014-04-03 14:43:30 -07001085 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001086
Ray Milkey269ffb92014-04-03 14:43:30 -07001087 @Override
1088 public boolean hasLayer3Configuration() {
1089 return !interfaces.isEmpty();
1090 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001091
Ray Milkey269ffb92014-04-03 14:43:30 -07001092 @Override
1093 public MACAddress getRouterMacAddress() {
1094 return bgpdMacAddress;
1095 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001096
Ray Milkey269ffb92014-04-03 14:43:30 -07001097 @Override
1098 public short getVlan() {
1099 return vlan;
1100 }
pingping-lin1ada7ce2014-08-14 13:45:22 -07001101
pingping-lin0426dee2014-08-27 15:03:17 -07001102 @Override
1103 public Set<SwitchPort> getExternalSwitchPorts() {
1104 return Collections.unmodifiableSet(externalNetworkSwitchPorts);
1105 }
1106
pingping-lina2cbfad2013-03-07 08:39:21 +08001107}