blob: 3ff60584477793c2c104e6984bf37e09b4d7556b [file] [log] [blame]
HIGUCHI Yutaea60e5f2013-06-12 11:10:21 -07001package net.onrc.onos.ofcontroller.bgproute;
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;
Jonathan Hart98957bf2013-07-01 14:49:24 +12009import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070010import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070011import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120012import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120013import java.util.concurrent.BlockingQueue;
14import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120015import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120016import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080019
Jonathan Hart61ba9372013-05-19 20:10:29 -070020import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070021import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart64c0b202013-08-20 15:45:07 +120022import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120027import net.floodlightcontroller.core.util.SingletonTask;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070028import net.floodlightcontroller.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120029import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080030import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120031import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080032import net.floodlightcontroller.topology.ITopologyListener;
33import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120034import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120035import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
Jonathan Hart98957bf2013-07-01 14:49:24 +120036import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
Jonathan Hartebba1e12013-10-29 11:37:02 -070037import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120038import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070039import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
40import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harte7694532013-09-12 12:34:46 +120041import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart7e466b32013-11-04 16:31:48 -080042import net.onrc.onos.ofcontroller.proxyarp.BgpProxyArpManager;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120043import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
Jonathan Hart5afde492013-10-01 12:30:53 +130044import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070045import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070046import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070047import net.onrc.onos.ofcontroller.topology.TopologyManager;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070048import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120049import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070050import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070051import net.onrc.onos.ofcontroller.util.Port;
52import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080053import net.sf.json.JSONArray;
54import net.sf.json.JSONObject;
55import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080056
Jonathan Hartd1f23252013-06-13 15:17:05 +120057import org.codehaus.jackson.JsonParseException;
58import org.codehaus.jackson.map.JsonMappingException;
59import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070060import org.openflow.protocol.OFFlowMod;
61import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070062import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120063import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070064import org.openflow.protocol.OFType;
65import org.openflow.protocol.action.OFAction;
66import org.openflow.protocol.action.OFActionDataLayerDestination;
67import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120068import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080069import org.slf4j.Logger;
70import org.slf4j.LoggerFactory;
71
Jonathan Hart4dfc3652013-08-02 20:22:36 +120072import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120073import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120074import com.google.common.collect.Multimaps;
75import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120076import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120077import com.google.common.util.concurrent.ThreadFactoryBuilder;
78
Jonathan Hart1236a9b2013-06-18 22:10:05 +120079public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120080 ITopologyListener, IArpRequester,
Jonathan Harta8887642013-10-28 13:46:54 -070081 IOFSwitchListener, IConfigInfoService,
Jonathan Hart5afde492013-10-01 12:30:53 +130082 IProxyArpService {
pingping-lina2cbfad2013-03-07 08:39:21 +080083
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070084 private final static Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080085
Jonathan Hartf247ee72013-10-18 18:57:28 -070086 private IFloodlightProviderService floodlightProvider;
Jonathan Hart3a326122013-10-21 11:51:13 -070087 private ITopologyService topologyService;
Jonathan Hartf247ee72013-10-18 18:57:28 -070088 private ITopologyNetService topologyNetService;
89 private ILinkDiscoveryService linkDiscoveryService;
90 private IRestApiService restApi;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070091
Jonathan Hart7e466b32013-11-04 16:31:48 -080092 private BgpProxyArpManager proxyArp;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120093
Jonathan Hartf247ee72013-10-18 18:57:28 -070094 private IPatriciaTrie<RibEntry> ptree;
95 private IPatriciaTrie<Interface> interfacePtrie;
96 private BlockingQueue<RibUpdate> ribUpdates;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120097
Jonathan Hartf247ee72013-10-18 18:57:28 -070098 private String bgpdRestIp;
99 private String routerId;
100 private String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700101
102 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
103 //the controller/OS should hand out cookie IDs to prevent conflicts.
Jonathan Hartf247ee72013-10-18 18:57:28 -0700104 private final long APP_COOKIE = 0xa0000000000000L;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700105 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Jonathan Hartf247ee72013-10-18 18:57:28 -0700106 private final long L2_FWD_COOKIE = APP_COOKIE + 1;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700107 //Cookie for flows in ingress switches that rewrite the MAC address
Jonathan Hartf247ee72013-10-18 18:57:28 -0700108 private final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200109 //Cookie for flows that setup BGP paths
Jonathan Hartf247ee72013-10-18 18:57:28 -0700110 private final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200111 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
112 //need to be higher priority than this otherwise the rewrite may not get done
Jonathan Hartf247ee72013-10-18 18:57:28 -0700113 private final short SDNIP_PRIORITY = 10;
114 private final short ARP_PRIORITY = 20;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700115
Jonathan Hartf247ee72013-10-18 18:57:28 -0700116 private final short BGP_PORT = 179;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200117
Jonathan Hartf247ee72013-10-18 18:57:28 -0700118 private final int TOPO_DETECTION_WAIT = 2; //seconds
Jonathan Hart98957bf2013-07-01 14:49:24 +1200119
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200120 //Configuration stuff
Jonathan Hartf247ee72013-10-18 18:57:28 -0700121 private List<String> switches;
122 private Map<String, Interface> interfaces;
123 private Map<InetAddress, BgpPeer> bgpPeers;
124 private SwitchPort bgpdAttachmentPoint;
125 private MACAddress bgpdMacAddress;
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700126 private short vlan;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200127
128 //True when all switches have connected
Jonathan Hartf247ee72013-10-18 18:57:28 -0700129 private volatile boolean switchesConnected = false;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200130 //True when we have a full mesh of shortest paths between gateways
Jonathan Hartf247ee72013-10-18 18:57:28 -0700131 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200132
Jonathan Hartf247ee72013-10-18 18:57:28 -0700133 private ArrayList<LDUpdate> linkUpdates;
134 private SingletonTask topologyChangeDetectorTask;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200135
Jonathan Hartf247ee72013-10-18 18:57:28 -0700136 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200137
Jonathan Hartf247ee72013-10-18 18:57:28 -0700138 private Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200139
Jonathan Hartf247ee72013-10-18 18:57:28 -0700140 private ExecutorService bgpUpdatesExecutor;
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200141
Jonathan Hartf247ee72013-10-18 18:57:28 -0700142 private Map<InetAddress, Path> pushedPaths;
143 private Map<Prefix, Path> prefixToPath;
144 private Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200145
Jonathan Hart1912afc2013-10-11 12:02:44 +1300146 private FlowCache flowCache;
147
Jonathan Hart3a326122013-10-21 11:51:13 -0700148 private volatile Topology topology = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200149
Jonathan Hartf247ee72013-10-18 18:57:28 -0700150 private class TopologyChangeDetector implements Runnable {
Jonathan Hart98957bf2013-07-01 14:49:24 +1200151 @Override
152 public void run() {
153 log.debug("Running topology change detection task");
154 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200155 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200156 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
157
158 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200159
160 Iterator<LDUpdate> it = linkUpdates.iterator();
161 while (it.hasNext()){
162 LDUpdate ldu = it.next();
163 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
164 ldu.getDst(), ldu.getDstPort());
165
166 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200167 it.remove();
168 }
169 }
170 }
171
Jonathan Hart64c0b202013-08-20 15:45:07 +1200172 if (!topologyReady) {
173 if (linkUpdates.isEmpty()){
174 //All updates have been seen in network map.
175 //We can check if topology is ready
176 log.debug("No known changes outstanding. Checking topology now");
177 checkStatus();
178 }
179 else {
180 //We know of some link updates that haven't propagated to the database yet
181 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
182 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
183 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200184 }
185 }
186 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700187
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700188 private void readConfiguration(String configFilename){
189 File gatewaysFile = new File(configFilename);
Jonathan Hartd1f23252013-06-13 15:17:05 +1200190 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700191
Jonathan Hartd1f23252013-06-13 15:17:05 +1200192 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200193 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
194
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200195 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200196 interfaces = new HashMap<String, Interface>();
197 for (Interface intf : config.getInterfaces()){
198 interfaces.put(intf.getName(), intf);
199 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200200 bgpPeers = new HashMap<InetAddress, BgpPeer>();
201 for (BgpPeer peer : config.getPeers()){
202 bgpPeers.put(peer.getIpAddress(), peer);
203 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200204
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200205 bgpdAttachmentPoint = new SwitchPort(
206 new Dpid(config.getBgpdAttachmentDpid()),
207 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200208
Jonathan Hart2f790d22013-08-15 14:01:24 +1200209 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700210 vlan = config.getVlan();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200211 } catch (JsonParseException e) {
212 log.error("Error in JSON file", e);
213 System.exit(1);
214 } catch (JsonMappingException e) {
215 log.error("Error in JSON file", e);
216 System.exit(1);
217 } catch (IOException e) {
218 log.error("Error reading JSON file", e);
219 System.exit(1);
220 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200221
222 //Populate the interface Patricia Trie
223 for (Interface intf : interfaces.values()) {
224 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
225 interfacePtrie.put(prefix, intf);
226 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700227 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800228
229 @Override
230 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700231 Collection<Class<? extends IFloodlightService>> l
232 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800233 l.add(IBgpRouteService.class);
Jonathan Harta8887642013-10-28 13:46:54 -0700234 l.add(IConfigInfoService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800235 return l;
236 }
237
238 @Override
239 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700240 Map<Class<? extends IFloodlightService>, IFloodlightService> m
241 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800242 m.put(IBgpRouteService.class, this);
Jonathan Harta8887642013-10-28 13:46:54 -0700243 m.put(IConfigInfoService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800244 return m;
245 }
246
pingping-lina2cbfad2013-03-07 08:39:21 +0800247 @Override
248 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700249 Collection<Class<? extends IFloodlightService>> l
250 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800251 l.add(IFloodlightProviderService.class);
252 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700253 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800254 return l;
255 }
256
257 @Override
258 public void init(FloodlightModuleContext context)
259 throws FloodlightModuleException {
260
Jonathan Hart29b972d2013-08-12 23:43:51 +1200261 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200262 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200263
264 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200265
pingping-lina2cbfad2013-03-07 08:39:21 +0800266 // Register floodlight provider and REST handler.
267 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700268 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200269 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200270 restApi = context.getServiceImpl(IRestApiService.class);
271
272 //TODO We'll initialise this here for now, but it should really be done as
273 //part of the controller core
Jonathan Harta8887642013-10-28 13:46:54 -0700274 //proxyArp = new ProxyArpManager(floodlightProvider, topologyService, this, restApi);
Jonathan Hart7e466b32013-11-04 16:31:48 -0800275 proxyArp = new BgpProxyArpManager();
276 proxyArp.init(floodlightProvider, topologyService, this, restApi);
277 //proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800278
Jonathan Hart98957bf2013-07-01 14:49:24 +1200279 linkUpdates = new ArrayList<LDUpdate>();
280 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
281 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700282
yoshif7424e42013-11-25 22:07:40 -0800283 topologyNetService = new TopologyManager(context);
Jonathan Hart98957bf2013-07-01 14:49:24 +1200284
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200285 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200286 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
287 HashMultimap.<InetAddress, RibUpdate>create());
288
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200289 pushedPaths = new HashMap<InetAddress, Path>();
290 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200291 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
292
Jonathan Hart1912afc2013-10-11 12:02:44 +1300293 flowCache = new FlowCache(floodlightProvider);
294
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200295 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
296 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
297
Jonathan Hart61ba9372013-05-19 20:10:29 -0700298 //Read in config values
299 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
300 if (bgpdRestIp == null){
301 log.error("BgpdRestIp property not found in config file");
302 System.exit(1);
303 }
304 else {
305 log.info("BgpdRestIp set to {}", bgpdRestIp);
306 }
307
308 routerId = context.getConfigParams(this).get("RouterId");
309 if (routerId == null){
310 log.error("RouterId property not found in config file");
311 System.exit(1);
312 }
313 else {
314 log.info("RouterId set to {}", routerId);
315 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200316
Jonathan Hart9575cb62013-07-05 13:43:49 +1200317 String configFilenameParameter = context.getConfigParams(this).get("configfile");
318 if (configFilenameParameter != null){
319 configFilename = configFilenameParameter;
320 }
321 log.debug("Config file set to {}", configFilename);
322
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700323 readConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200324 }
325
326 @Override
327 public void startUp(FloodlightModuleContext context) {
328 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700329 topologyService.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200330 floodlightProvider.addOFSwitchListener(this);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200331
Jonathan Hart7e466b32013-11-04 16:31:48 -0800332 proxyArp.startUp();
Jonathan Hart2f790d22013-08-15 14:01:24 +1200333
Jonathan Harta8887642013-10-28 13:46:54 -0700334 //floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200335
336 //Retrieve the RIB from BGPd during startup
337 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800338 }
339
Jonathan Hart29b972d2013-08-12 23:43:51 +1200340 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800341 return ptree;
342 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700343
344 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200345 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800346 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700347
pingping-line2a09ca2013-03-23 09:33:58 +0800348 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700349 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800350 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700351
pingping-line2a09ca2013-03-23 09:33:58 +0800352 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700353 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800354 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800355
Jonathan Hart61ba9372013-05-19 20:10:29 -0700356 private void retrieveRib(){
357 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
358 String response = RestClient.get(url);
359
360 if (response.equals("")){
361 return;
362 }
363
364 response = response.replaceAll("\"", "'");
365 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
366 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
367 String router_id = jsonObj.getString("router-id");
368
369 int size = rib_json_array.size();
370
371 log.info("Retrived RIB of {} entries from BGPd", size);
372
373 for (int j = 0; j < size; j++) {
374 JSONObject second_json_object = rib_json_array.getJSONObject(j);
375 String prefix = second_json_object.getString("prefix");
376 String nexthop = second_json_object.getString("nexthop");
377
378 //insert each rib entry into the local rib;
379 String[] substring = prefix.split("/");
380 String prefix1 = substring[0];
381 String mask1 = substring[1];
382
383 Prefix p;
384 try {
385 p = new Prefix(prefix1, Integer.valueOf(mask1));
386 } catch (NumberFormatException e) {
387 log.warn("Wrong mask format in RIB JSON: {}", mask1);
388 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200389 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700390 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
391 continue;
392 }
393
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200394 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200395
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200396 try {
397 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
398 } catch (InterruptedException e) {
399 log.debug("Interrupted while pushing onto update queue");
400 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700401 }
402 }
403
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200404 @Override
405 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200406 try {
407 ribUpdates.put(update);
408 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200409 log.debug("Interrupted while putting on ribUpdates queue", e);
410 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200411 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200412 }
413
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200414 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200415 Prefix prefix = update.getPrefix();
416
Jonathan Hart9ea31212013-08-12 21:40:34 +1200417 log.debug("Processing prefix add {}", prefix);
418
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200419 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200420
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200421 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200422 //There was an existing nexthop for this prefix. This update supersedes that,
423 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200424 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200425 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200426
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200427 if (update.getRibEntry().getNextHop().equals(
428 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200429 //Route originated by SDN domain
430 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200431 log.debug("Own route {} to {}", prefix,
432 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200433 return;
434 }
435
436 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200437 }
438
Jonathan Hart309889c2013-08-13 23:26:24 +1200439 private void _processRibAdd(RibUpdate update) {
440 Prefix prefix = update.getPrefix();
441 RibEntry rib = update.getRibEntry();
442
443 InetAddress dstIpAddress = rib.getNextHop();
444
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200445 //See if we know the MAC address of the next hop
Jonathan Hartabad6a52013-09-30 18:17:21 +1300446 MACAddress nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200447
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200448 //Find the attachment point (egress interface) of the next hop
449 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200450 if (bgpPeers.containsKey(dstIpAddress)) {
451 //Route to a peer
452 log.debug("Route to peer {}", dstIpAddress);
453 BgpPeer peer = bgpPeers.get(dstIpAddress);
454 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200455 }
456 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200457 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200458 log.debug("Route to non-peer {}", dstIpAddress);
459 egressInterface = interfacePtrie.match(
460 new Prefix(dstIpAddress.getAddress(), 32));
461 if (egressInterface == null) {
462 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
463 return;
464 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200465 }
466
467 if (nextHopMacAddress == null) {
468 prefixesWaitingOnArp.put(dstIpAddress,
469 new RibUpdate(Operation.UPDATE, prefix, rib));
470 proxyArp.sendArpRequest(dstIpAddress, this, true);
471 return;
472 }
473 else {
474 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200475 //If the prefix is for a non-peer we need to ensure there's a path,
476 //and push one if there isn't.
477 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200478 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200479 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300480 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200481 pushedPaths.put(dstIpAddress, path);
482 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200483
484 path.incrementUsers();
485 prefixToPath.put(prefix, path);
486 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200487
488 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200489 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
490 }
491 }
492
Jonathan Hartabad6a52013-09-30 18:17:21 +1300493 private void addPrefixFlows(Prefix prefix, Interface egressInterface, MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700494 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300495 prefix, nextHopMacAddress);
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200496
497 //We only need one flow mod per switch, so pick one interface on each switch
498 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
499 for (Interface intf : interfaces.values()) {
500 if (!srcInterfaces.containsKey(intf.getDpid())
Jonathan Hart45107222013-10-22 17:35:04 -0700501 && !intf.equals(egressInterface)) {
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200502 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200503 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200504 }
505
506 //Add a flow to rewrite mac for this prefix to all other border switches
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200507 for (Interface srcInterface : srcInterfaces.values()) {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200508 DataPath shortestPath;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700509 if (topology == null) {
510 shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200511 srcInterface.getSwitchPort(),
512 egressInterface.getSwitchPort());
513 }
514 else {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700515 shortestPath = topologyNetService.getTopologyShortestPath(
516 topology, srcInterface.getSwitchPort(),
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200517 egressInterface.getSwitchPort());
518 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200519
520 if (shortestPath == null){
521 log.debug("Shortest path between {} and {} not found",
522 srcInterface.getSwitchPort(),
523 egressInterface.getSwitchPort());
524 return; // just quit here?
525 }
526
527 //Set up the flow mod
528 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
529 .getMessage(OFType.FLOW_MOD);
530
531 fm.setIdleTimeout((short)0)
532 .setHardTimeout((short)0)
533 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
534 .setCookie(MAC_RW_COOKIE)
535 .setCommand(OFFlowMod.OFPFC_ADD)
536 .setPriority(SDNIP_PRIORITY)
537 .setLengthU(OFFlowMod.MINIMUM_LENGTH
538 + OFActionDataLayerDestination.MINIMUM_LENGTH
539 + OFActionOutput.MINIMUM_LENGTH);
540
541 OFMatch match = new OFMatch();
542 match.setDataLayerType(Ethernet.TYPE_IPv4);
543 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
544
545 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
546 fm.setMatch(match);
547
548 //Set up MAC rewrite action
549 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartabad6a52013-09-30 18:17:21 +1300550 macRewriteAction.setDataLayerAddress(nextHopMacAddress.toBytes());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200551
552 //Set up output action
553 OFActionOutput outputAction = new OFActionOutput();
554 outputAction.setMaxLength((short)0xffff);
555 Port outputPort = shortestPath.flowEntries().get(0).outPort();
556 outputAction.setPort(outputPort.value());
557
558 List<OFAction> actions = new ArrayList<OFAction>();
559 actions.add(macRewriteAction);
560 actions.add(outputAction);
561 fm.setActions(actions);
562
Jonathan Hart1912afc2013-10-11 12:02:44 +1300563 pushedFlows.put(prefix, new PushedFlowMod(srcInterface.getDpid(), fm));
564 flowCache.write(srcInterface.getDpid(), fm);
565
566 /*
567 * XXX Rate limit hack!
568 * This should be solved properly by adding a rate limiting
569 * layer on top of the switches if we know they need it.
570 */
571 try {
Jonathan Hart9971e1c2013-09-17 10:47:40 +1200572 Thread.sleep(1);
Jonathan Hart65139e42013-09-13 16:52:25 +1200573 } catch (InterruptedException e) {
574 // TODO handle this properly
575 log.error("Interrupted", e);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200576 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200577 }
578 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200579
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200580 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200581 Prefix prefix = update.getPrefix();
582
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200583 if (ptree.remove(prefix, update.getRibEntry())) {
584 /*
585 * Only delete flows if an entry was actually removed from the trie.
586 * If no entry was removed, the <prefix, nexthop> wasn't there so
587 * it's probably already been removed and we don't need to do anything
588 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200589 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200590 }
591 }
592
593 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
594 deletePrefixFlows(prefix);
595
596 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200597
Jonathan Hart309889c2013-08-13 23:26:24 +1200598 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
599 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200600 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200601
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200602 if (path != null) {
603 //path could be null if we added to the Ptree but didn't push
604 //flows yet because we were waiting to resolve ARP
Jonathan Hart309889c2013-08-13 23:26:24 +1200605
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200606 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200607 if (path.getUsers() <= 0 && !path.isPermanent()) {
608 deletePath(path);
609 pushedPaths.remove(path.getDstIpAddress());
610 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200611 }
612 }
613 }
614
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200615 private void deletePrefixFlows(Prefix prefix) {
616 log.debug("Deleting flows for prefix {}", prefix);
617
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200618 Collection<PushedFlowMod> pushedFlowMods
619 = pushedFlows.removeAll(prefix);
620
621 for (PushedFlowMod pfm : pushedFlowMods) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200622 if (log.isTraceEnabled()) {
623 log.trace("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
624 new Object[] {HexString.toHexString(pfm.getDpid()),
625 pfm.getFlowMod().getMatch().getNetworkDestination() +
626 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
627 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
628 .getDataLayerAddress())});
629 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200630
631 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
632 }
633 }
634
635 private void deletePath(Path path) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200636 log.debug("Deleting flows for path to {}",
637 path.getDstIpAddress().getHostAddress());
638
Jonathan Hart309889c2013-08-13 23:26:24 +1200639 for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200640 if (log.isTraceEnabled()) {
641 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
642 new Object[] {HexString.toHexString(pfm.getDpid()),
643 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
644 });
645 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200646
647 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
648 }
649 }
650
651 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
Jonathan Hart1912afc2013-10-11 12:02:44 +1300652 flowCache.delete(dpid, addFlowMod);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200653 }
654
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200655 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200656 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200657
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700658 /*
659 * On startup we need to calculate a full mesh of paths between all gateway
660 * switches
661 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200662 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700663 //For each border router, calculate and install a path from every other
664 //border switch to said border router. However, don't install the entry
665 //in to the first hop switch, as we need to install an entry to rewrite
666 //for each prefix received. This will be done later when prefixes have
667 //actually been received.
668
Jonathan Hartc824ad02013-07-03 15:58:45 +1200669 for (BgpPeer peer : bgpPeers.values()) {
670 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200671
Jonathan Hart309889c2013-08-13 23:26:24 +1200672 //We know there's not already a Path here pushed, because this is
673 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200674 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200675 path.setPermanent();
676
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200677 //See if we know the MAC address of the peer. If not we can't
678 //do anything until we learn it
Jonathan Hartabad6a52013-09-30 18:17:21 +1300679 MACAddress macAddress = proxyArp.getMacAddress(peer.getIpAddress());
680 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200681 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
682 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200683 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700684
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200685 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
686 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700687 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200688
689 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300690 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700691 }
692 }
693
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200694 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200695 Interface dstInterface = path.getDstInterface();
696
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200697 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
698 dstMacAddress);
699
Jonathan Hart309889c2013-08-13 23:26:24 +1200700 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
701
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200702 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -0700703 if (dstInterface.equals(srcInterface)){
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200704 continue;
705 }
706
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200707 DataPath shortestPath;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700708 if (topology == null) {
709 shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200710 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
711 }
712 else {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700713 shortestPath = topologyNetService.getTopologyShortestPath(topology,
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200714 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
715 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200716
717 if (shortestPath == null){
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200718 log.warn("Shortest path between {} and {} not found",
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200719 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200720 return;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200721 }
722
Jonathan Hart1912afc2013-10-11 12:02:44 +1300723 List<PushedFlowMod> pushedFlowMods = installPath(shortestPath.flowEntries(), dstMacAddress);
724 pushedFlows.addAll(pushedFlowMods);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200725 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200726
727 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200728 }
729
Jonathan Hart309889c2013-08-13 23:26:24 +1200730 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
731 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
732
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700733 //Set up the flow mod
734 OFFlowMod fm =
735 (OFFlowMod) floodlightProvider.getOFMessageFactory()
736 .getMessage(OFType.FLOW_MOD);
737
738 OFActionOutput action = new OFActionOutput();
739 action.setMaxLength((short)0xffff);
740 List<OFAction> actions = new ArrayList<OFAction>();
741 actions.add(action);
742
743 fm.setIdleTimeout((short)0)
744 .setHardTimeout((short)0)
745 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
746 .setCookie(L2_FWD_COOKIE)
747 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hartbdc87462013-09-24 15:03:23 +1200748 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700749 .setActions(actions)
750 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
751
752 //Don't push the first flow entry. We need to push entries in the
753 //first switch based on IP prefix which we don't know yet.
754 for (int i = 1; i < flowEntries.size(); i++){
755 FlowEntry flowEntry = flowEntries.get(i);
756
757 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200758 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700759 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
760 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
761
762 fm.setMatch(match);
763
Jonathan Hart1912afc2013-10-11 12:02:44 +1300764 flowMods.add(new PushedFlowMod(flowEntry.dpid().value(), fm));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700765
Jonathan Hart1912afc2013-10-11 12:02:44 +1300766 flowCache.write(flowEntry.dpid().value(), fm);
767
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700768 try {
769 fm = fm.clone();
770 } catch (CloneNotSupportedException e1) {
771 log.error("Failure cloning flow mod", e1);
772 }
773 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200774
775 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700776 }
777
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200778 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200779 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200780 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
781
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700782 DataPath path = topologyNetService.getDatabaseShortestPath(
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200783 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
784
785 if (path == null){
786 log.debug("Unable to compute path for BGP traffic for {}",
787 bgpPeer.getIpAddress());
788 continue;
789 }
790
791 //Set up the flow mod
792 OFFlowMod fm =
793 (OFFlowMod) floodlightProvider.getOFMessageFactory()
794 .getMessage(OFType.FLOW_MOD);
795
796 OFActionOutput action = new OFActionOutput();
797 action.setMaxLength((short)0xffff);
798 List<OFAction> actions = new ArrayList<OFAction>();
799 actions.add(action);
800
801 fm.setIdleTimeout((short)0)
802 .setHardTimeout((short)0)
803 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
804 .setCookie(BGP_COOKIE)
805 .setCommand(OFFlowMod.OFPFC_ADD)
806 .setPriority(SDNIP_PRIORITY)
807 .setActions(actions)
808 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
809
810 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
811 OFMatch forwardMatchSrc = new OFMatch();
812
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200813 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
814 + "/32";
815 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
816 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200817
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200818 //Common match fields
819 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200820 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300821 //forwardMatchSrc.setTransportDestination(BGP_PORT);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200822 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
823 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
824
825
826 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
827
828 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
829 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
830
831 OFMatch forwardMatchDst = forwardMatchSrc.clone();
832
833 forwardMatchSrc.setTransportSource(BGP_PORT);
834 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
835 forwardMatchDst.setTransportDestination(BGP_PORT);
836 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
837
838 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
839 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
840
841 OFMatch reverseMatchDst = reverseMatchSrc.clone();
842
843 reverseMatchSrc.setTransportSource(BGP_PORT);
844 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
845 reverseMatchDst.setTransportDestination(BGP_PORT);
846 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
847
848 fm.setMatch(forwardMatchSrc);
849
Jonathan Hart38c84932013-08-10 17:49:27 +1200850 OFMatch forwardIcmpMatch = new OFMatch();
851 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
852 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
853 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
854 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
855
856 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
857 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
858 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
859
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200860 for (FlowEntry flowEntry : path.flowEntries()){
861 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
862 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200863 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200864 try {
865 forwardFlowModSrc = fm.clone();
866 forwardFlowModDst = fm.clone();
867 reverseFlowModSrc = fm.clone();
868 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200869 forwardIcmp = fm.clone();
870 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200871 } catch (CloneNotSupportedException e) {
872 log.warn("Clone failed", e);
873 continue;
874 }
875
876 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
877 forwardFlowModSrc.setMatch(forwardMatchSrc);
878 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
879 .setPort(flowEntry.outPort().value());
880
881 forwardMatchDst.setInputPort(flowEntry.inPort().value());
882 forwardFlowModDst.setMatch(forwardMatchDst);
883 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
884 .setPort(flowEntry.outPort().value());
885
886 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
887 reverseFlowModSrc.setMatch(reverseMatchSrc);
888 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
889 .setPort(flowEntry.inPort().value());
890
891 reverseMatchDst.setInputPort(flowEntry.outPort().value());
892 reverseFlowModDst.setMatch(reverseMatchDst);
893 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
894 .setPort(flowEntry.inPort().value());
895
Jonathan Hart38c84932013-08-10 17:49:27 +1200896 ((OFActionOutput)forwardIcmp.getActions().get(0))
897 .setPort(flowEntry.outPort().value());
898 forwardIcmp.setMatch(forwardIcmpMatch);
899
900 ((OFActionOutput)reverseIcmp.getActions().get(0))
901 .setPort(flowEntry.inPort().value());
902 reverseIcmp.setMatch(reverseIcmpMatch);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200903
Jonathan Hart1912afc2013-10-11 12:02:44 +1300904 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(6);
905 flowModList.add(forwardFlowModSrc);
906 flowModList.add(forwardFlowModDst);
907 flowModList.add(reverseFlowModSrc);
908 flowModList.add(reverseFlowModDst);
909 flowModList.add(forwardIcmp);
910 flowModList.add(reverseIcmp);
911 flowCache.write(flowEntry.dpid().value(), flowModList);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200912 }
913 }
914 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200915
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200916 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +1300917 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
918 log.debug("Received ARP response: {} => {}",
919 ipAddress.getHostAddress(), macAddress);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200920
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200921 /*
922 * We synchronize on this to prevent changes to the ptree while we're pushing
923 * flows to the switches. If the ptree changes, the ptree and switches
924 * could get out of sync.
925 */
926 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200927 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200928
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200929 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200930 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300931 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200932 path.getDstInterface().getSwitchPort()});
933 //These paths should always be to BGP peers. Paths to non-peers are
934 //handled once the first prefix is ready to push
935 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200936 //A path already got pushed to this endpoint while we were waiting
937 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200938 if (path.isPermanent()) {
939 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200940 }
941 }
942 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300943 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200944 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200945 }
946 }
947
Jonathan Hart309889c2013-08-13 23:26:24 +1200948 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
949
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200950 for (RibUpdate update : prefixesToPush) {
951 //These will always be adds
952
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200953 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200954 if (rib != null && rib.equals(update.getRibEntry())) {
955 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200956 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200957 //We only push prefix flows if the prefix is still in the ptree
958 //and the next hop is the same as our update. The prefix could
959 //have been removed while we were waiting for the ARP, or the
960 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200961 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200962 } else {
963 log.debug("Received ARP response, but {},{} is no longer in ptree",
964 update.getPrefix(), update.getRibEntry());
965 }
966 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200967 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200968 }
969
Jonathan Hartc82051c2013-08-24 15:12:20 +1200970 private void setupArpFlows() {
971 OFMatch match = new OFMatch();
972 match.setDataLayerType(Ethernet.TYPE_ARP);
973 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
974
975 OFFlowMod fm = new OFFlowMod();
976 fm.setMatch(match);
977
978 OFActionOutput action = new OFActionOutput();
979 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
980 action.setMaxLength((short)0xffff);
981 List<OFAction> actions = new ArrayList<OFAction>(1);
982 actions.add(action);
983 fm.setActions(actions);
984
985 fm.setIdleTimeout((short)0)
986 .setHardTimeout((short)0)
987 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
988 .setCookie(0)
989 .setCommand(OFFlowMod.OFPFC_ADD)
990 .setPriority(ARP_PRIORITY)
991 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
992
993 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +1300994 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +1200995 }
996 }
997
Jonathan Hartf886fa12013-09-18 14:46:29 +1200998 private void setupDefaultDropFlows() {
999 OFFlowMod fm = new OFFlowMod();
1000 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001001 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Jonathan Hartf886fa12013-09-18 14:46:29 +12001002
1003 fm.setIdleTimeout((short)0)
1004 .setHardTimeout((short)0)
1005 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1006 .setCookie(0)
1007 .setCommand(OFFlowMod.OFPFC_ADD)
1008 .setPriority((short)0)
1009 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
1010
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001011 OFFlowMod fmLLDP;
1012 OFFlowMod fmBDDP;
1013 try {
1014 fmLLDP = fm.clone();
1015 fmBDDP = fm.clone();
1016 } catch (CloneNotSupportedException e1) {
1017 log.error("Error cloning flow mod", e1);
1018 return;
1019 }
1020
1021 OFMatch matchLLDP = new OFMatch();
1022 matchLLDP.setDataLayerType((short)0x8942);
1023 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1024 fmLLDP.setMatch(matchLLDP);
1025
1026 OFMatch matchBDDP = new OFMatch();
1027 matchBDDP.setDataLayerType((short)0x88cc);
1028 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1029 fmBDDP.setMatch(matchBDDP);
1030
1031 OFActionOutput action = new OFActionOutput();
1032 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1033 action.setMaxLength((short)0xffff);
1034 List<OFAction> actions = new ArrayList<OFAction>(1);
1035 actions.add(action);
1036
1037 fmLLDP.setActions(actions);
1038 fmBDDP.setActions(actions);
1039
1040 fmLLDP.setPriority(ARP_PRIORITY);
1041 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1042 fmBDDP.setPriority(ARP_PRIORITY);
1043 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1044
Jonathan Hart1912afc2013-10-11 12:02:44 +13001045 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1046 flowModList.add(fm);
1047 flowModList.add(fmLLDP);
1048 flowModList.add(fmBDDP);
1049
Jonathan Hartf886fa12013-09-18 14:46:29 +12001050 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001051 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001052 }
1053 }
1054
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001055 private void beginRouting(){
1056 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001057 topology = topologyNetService.newDatabaseTopology();
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001058
Jonathan Hartc82051c2013-08-24 15:12:20 +12001059 setupArpFlows();
Jonathan Hartf886fa12013-09-18 14:46:29 +12001060 setupDefaultDropFlows();
Jonathan Hartc82051c2013-08-24 15:12:20 +12001061
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001062 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001063 setupFullMesh();
Jonathan Harte7694532013-09-12 12:34:46 +12001064
1065 //Suppress link discovery on external-facing router ports
1066 for (Interface intf : interfaces.values()) {
1067 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1068 }
1069
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001070 bgpUpdatesExecutor.execute(new Runnable() {
1071 @Override
1072 public void run() {
1073 doUpdatesThread();
1074 }
1075 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001076 }
1077
1078 private void checkSwitchesConnected(){
1079 for (String dpid : switches){
1080 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1081 log.debug("Not all switches are here yet");
1082 return;
1083 }
1084 }
1085 switchesConnected = true;
1086 }
1087
Jonathan Hartc824ad02013-07-03 15:58:45 +12001088 //Actually we only need to go half way round to verify full mesh connectivity
1089 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001090 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001091 for (Interface dstInterface : interfaces.values()) {
1092 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -07001093 if (dstInterface.equals(srcInterface)) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001094 continue;
1095 }
1096
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001097 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001098 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001099
1100 if (shortestPath == null){
1101 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001102 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001103 return;
1104 }
1105 }
1106 }
1107 topologyReady = true;
1108 }
1109
1110 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001111 if (!switchesConnected){
1112 checkSwitchesConnected();
1113 }
1114 boolean oldTopologyReadyStatus = topologyReady;
1115 if (switchesConnected && !topologyReady){
1116 checkTopologyReady();
1117 }
1118 if (!oldTopologyReadyStatus && topologyReady){
1119 beginRouting();
1120 }
1121 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001122
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001123 private void doUpdatesThread() {
1124 boolean interrupted = false;
1125 try {
1126 while (true) {
1127 try {
1128 RibUpdate update = ribUpdates.take();
1129 switch (update.getOperation()){
1130 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001131 if (validateUpdate(update)) {
1132 processRibAdd(update);
1133 }
1134 else {
1135 log.debug("Rib UPDATE out of order: {} via {}",
1136 update.getPrefix(), update.getRibEntry().getNextHop());
1137 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001138 break;
1139 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001140 if (validateUpdate(update)) {
1141 processRibDelete(update);
1142 }
1143 else {
1144 log.debug("Rib DELETE out of order: {} via {}",
1145 update.getPrefix(), update.getRibEntry().getNextHop());
1146 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001147 break;
1148 }
1149 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001150 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001151 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001152 } catch (Exception e) {
1153 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001154 }
1155 }
1156 } finally {
1157 if (interrupted) {
1158 Thread.currentThread().interrupt();
1159 }
1160 }
1161 }
Jonathan Harte4c98692013-10-18 17:40:03 -07001162
1163 private boolean validateUpdate(RibUpdate update) {
1164 RibEntry newEntry = update.getRibEntry();
1165 RibEntry oldEntry = ptree.lookup(update.getPrefix());
1166
1167 //If there is no existing entry we must assume this is the most recent
1168 //update. However this might not always be the case as we might have a
1169 //POST then DELETE reordering.
1170 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1171 if (oldEntry == null) {
1172 return true;
1173 }
1174
1175 // This handles the case where routes are gathered in the initial
1176 // request because they don't have sequence number info
1177 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1178 return true;
1179 }
1180
1181 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1182 return true;
1183 }
1184 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1185 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1186 return true;
1187 }
1188 else {
1189 return false;
1190 }
1191 }
1192 else {
1193 return false;
1194 }
1195 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001196
1197 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001198 public void topologyChanged() {
1199 if (topologyReady) {
1200 return;
1201 }
1202
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001203 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001204 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001205 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1206 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001207 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001208 refreshNeeded = true;
1209 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001210
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001211 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001212
Jonathan Hart98957bf2013-07-01 14:49:24 +12001213 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1214 synchronized (linkUpdates) {
1215 linkUpdates.add(ldu);
1216 }
1217 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001218 }
1219
Jonathan Hart64c0b202013-08-20 15:45:07 +12001220 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001221 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001222 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001223 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001224
1225 @Override
1226 public void addedSwitch(IOFSwitch sw) {
1227 if (!topologyReady) {
1228 sw.clearAllFlowMods();
1229 }
Jonathan Hart1912afc2013-10-11 12:02:44 +13001230
1231 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001232 }
1233
1234 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001235 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001236
1237 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001238 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001239
1240 @Override
1241 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001242 return "BgpRoute";
1243 }
1244
1245 /*
Jonathan Harta8887642013-10-28 13:46:54 -07001246 * IConfigInfoService methods
Jonathan Hart08ee8522013-09-22 17:34:43 +12001247 */
1248
1249 @Override
1250 public boolean isInterfaceAddress(InetAddress address) {
1251 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1252 return (intf != null && intf.getIpAddress().equals(address));
1253 }
1254
1255 @Override
1256 public boolean inConnectedNetwork(InetAddress address) {
1257 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1258 return (intf != null && !intf.getIpAddress().equals(address));
1259 }
1260
1261 @Override
1262 public boolean fromExternalNetwork(long inDpid, short inPort) {
1263 for (Interface intf : interfaces.values()) {
1264 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1265 return true;
1266 }
1267 }
1268 return false;
1269 }
1270
1271 @Override
1272 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1273 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1274 }
1275
1276 @Override
1277 public boolean hasLayer3Configuration() {
1278 return !interfaces.isEmpty();
1279 }
1280
1281 @Override
1282 public MACAddress getRouterMacAddress() {
1283 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001284 }
Jonathan Harta8887642013-10-28 13:46:54 -07001285
1286 @Override
1287 public short getVlan() {
1288 return vlan;
1289 }
Jonathan Hart5afde492013-10-01 12:30:53 +13001290
1291 /*
1292 * TODO This is a hack to get the REST API to work for ProxyArpManager.
1293 * The REST API is currently tied to the Floodlight module system and we
1294 * need to separate it to allow ONOS modules to use it. For now we will
1295 * proxy calls through to the ProxyArpManager (which is not a Floodlight
1296 * module) through this class which is a module.
1297 */
1298 @Override
1299 public MACAddress getMacAddress(InetAddress ipAddress) {
1300 return proxyArp.getMacAddress(ipAddress);
1301 }
1302
1303 @Override
1304 public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
1305 boolean retry) {
1306 proxyArp.sendArpRequest(ipAddress, requester, retry);
1307 }
1308
1309 @Override
1310 public List<String> getMappings() {
1311 return proxyArp.getMappings();
1312 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001313}