blob: 4f6c31007d0255db06a557739d3e6fe5b8791512 [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;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070044import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070045import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070046import net.onrc.onos.ofcontroller.topology.TopologyManager;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120048import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070049import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070050import net.onrc.onos.ofcontroller.util.Port;
51import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080052import net.sf.json.JSONArray;
53import net.sf.json.JSONObject;
54import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080055
Jonathan Hartd1f23252013-06-13 15:17:05 +120056import org.codehaus.jackson.JsonParseException;
57import org.codehaus.jackson.map.JsonMappingException;
58import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070059import org.openflow.protocol.OFFlowMod;
60import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070061import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120062import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070063import org.openflow.protocol.OFType;
64import org.openflow.protocol.action.OFAction;
65import org.openflow.protocol.action.OFActionDataLayerDestination;
66import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120067import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080068import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
Jonathan Hart4dfc3652013-08-02 20:22:36 +120071import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120072import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120073import com.google.common.collect.Multimaps;
74import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120075import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120076import com.google.common.util.concurrent.ThreadFactoryBuilder;
77
Jonathan Hart1236a9b2013-06-18 22:10:05 +120078public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120079 ITopologyListener, IArpRequester,
Jonathan Hart7804bea2014-01-07 10:50:52 -080080 IOFSwitchListener, IConfigInfoService {
pingping-lina2cbfad2013-03-07 08:39:21 +080081
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070082 private final static Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080083
Jonathan Hartf247ee72013-10-18 18:57:28 -070084 private IFloodlightProviderService floodlightProvider;
Jonathan Hart3a326122013-10-21 11:51:13 -070085 private ITopologyService topologyService;
Jonathan Hartf247ee72013-10-18 18:57:28 -070086 private ITopologyNetService topologyNetService;
87 private ILinkDiscoveryService linkDiscoveryService;
88 private IRestApiService restApi;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070089
Jonathan Hart7e466b32013-11-04 16:31:48 -080090 private BgpProxyArpManager proxyArp;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120091
Jonathan Hartf247ee72013-10-18 18:57:28 -070092 private IPatriciaTrie<RibEntry> ptree;
93 private IPatriciaTrie<Interface> interfacePtrie;
94 private BlockingQueue<RibUpdate> ribUpdates;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120095
Jonathan Hartf247ee72013-10-18 18:57:28 -070096 private String bgpdRestIp;
97 private String routerId;
98 private String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070099
100 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
101 //the controller/OS should hand out cookie IDs to prevent conflicts.
Jonathan Hartf247ee72013-10-18 18:57:28 -0700102 private final long APP_COOKIE = 0xa0000000000000L;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700103 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Jonathan Hartf247ee72013-10-18 18:57:28 -0700104 private final long L2_FWD_COOKIE = APP_COOKIE + 1;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700105 //Cookie for flows in ingress switches that rewrite the MAC address
Jonathan Hartf247ee72013-10-18 18:57:28 -0700106 private final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200107 //Cookie for flows that setup BGP paths
Jonathan Hartf247ee72013-10-18 18:57:28 -0700108 private final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200109 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
110 //need to be higher priority than this otherwise the rewrite may not get done
Jonathan Hartf247ee72013-10-18 18:57:28 -0700111 private final short SDNIP_PRIORITY = 10;
112 private final short ARP_PRIORITY = 20;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700113
Jonathan Hartf247ee72013-10-18 18:57:28 -0700114 private final short BGP_PORT = 179;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200115
Jonathan Hartf247ee72013-10-18 18:57:28 -0700116 private final int TOPO_DETECTION_WAIT = 2; //seconds
Jonathan Hart98957bf2013-07-01 14:49:24 +1200117
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200118 //Configuration stuff
Jonathan Hartf247ee72013-10-18 18:57:28 -0700119 private List<String> switches;
120 private Map<String, Interface> interfaces;
121 private Map<InetAddress, BgpPeer> bgpPeers;
122 private SwitchPort bgpdAttachmentPoint;
123 private MACAddress bgpdMacAddress;
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700124 private short vlan;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200125
126 //True when all switches have connected
Jonathan Hartf247ee72013-10-18 18:57:28 -0700127 private volatile boolean switchesConnected = false;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200128 //True when we have a full mesh of shortest paths between gateways
Jonathan Hartf247ee72013-10-18 18:57:28 -0700129 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200130
Jonathan Hartf247ee72013-10-18 18:57:28 -0700131 private ArrayList<LDUpdate> linkUpdates;
132 private SingletonTask topologyChangeDetectorTask;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200133
Jonathan Hartf247ee72013-10-18 18:57:28 -0700134 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200135
Jonathan Hartf247ee72013-10-18 18:57:28 -0700136 private Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200137
Jonathan Hartf247ee72013-10-18 18:57:28 -0700138 private ExecutorService bgpUpdatesExecutor;
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200139
Jonathan Hartf247ee72013-10-18 18:57:28 -0700140 private Map<InetAddress, Path> pushedPaths;
141 private Map<Prefix, Path> prefixToPath;
142 private Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200143
Jonathan Hart1912afc2013-10-11 12:02:44 +1300144 private FlowCache flowCache;
145
Jonathan Hart3a326122013-10-21 11:51:13 -0700146 private volatile Topology topology = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200147
Jonathan Hartf247ee72013-10-18 18:57:28 -0700148 private class TopologyChangeDetector implements Runnable {
Jonathan Hart98957bf2013-07-01 14:49:24 +1200149 @Override
150 public void run() {
151 log.debug("Running topology change detection task");
152 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200153 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200154 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
155
156 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200157
158 Iterator<LDUpdate> it = linkUpdates.iterator();
159 while (it.hasNext()){
160 LDUpdate ldu = it.next();
161 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
162 ldu.getDst(), ldu.getDstPort());
163
164 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200165 it.remove();
166 }
167 }
168 }
169
Jonathan Hart64c0b202013-08-20 15:45:07 +1200170 if (!topologyReady) {
171 if (linkUpdates.isEmpty()){
172 //All updates have been seen in network map.
173 //We can check if topology is ready
174 log.debug("No known changes outstanding. Checking topology now");
175 checkStatus();
176 }
177 else {
178 //We know of some link updates that haven't propagated to the database yet
179 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
180 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
181 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200182 }
183 }
184 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700185
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700186 private void readConfiguration(String configFilename){
187 File gatewaysFile = new File(configFilename);
Jonathan Hartd1f23252013-06-13 15:17:05 +1200188 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700189
Jonathan Hartd1f23252013-06-13 15:17:05 +1200190 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200191 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
192
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200193 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200194 interfaces = new HashMap<String, Interface>();
195 for (Interface intf : config.getInterfaces()){
196 interfaces.put(intf.getName(), intf);
197 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200198 bgpPeers = new HashMap<InetAddress, BgpPeer>();
199 for (BgpPeer peer : config.getPeers()){
200 bgpPeers.put(peer.getIpAddress(), peer);
201 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200202
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200203 bgpdAttachmentPoint = new SwitchPort(
204 new Dpid(config.getBgpdAttachmentDpid()),
205 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200206
Jonathan Hart2f790d22013-08-15 14:01:24 +1200207 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700208 vlan = config.getVlan();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200209 } catch (JsonParseException e) {
210 log.error("Error in JSON file", e);
211 System.exit(1);
212 } catch (JsonMappingException e) {
213 log.error("Error in JSON file", e);
214 System.exit(1);
215 } catch (IOException e) {
216 log.error("Error reading JSON file", e);
217 System.exit(1);
218 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200219
220 //Populate the interface Patricia Trie
221 for (Interface intf : interfaces.values()) {
222 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
223 interfacePtrie.put(prefix, intf);
224 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700225 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800226
227 @Override
228 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700229 Collection<Class<? extends IFloodlightService>> l
230 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800231 l.add(IBgpRouteService.class);
Jonathan Harta8887642013-10-28 13:46:54 -0700232 l.add(IConfigInfoService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800233 return l;
234 }
235
236 @Override
237 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700238 Map<Class<? extends IFloodlightService>, IFloodlightService> m
239 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800240 m.put(IBgpRouteService.class, this);
Jonathan Harta8887642013-10-28 13:46:54 -0700241 m.put(IConfigInfoService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800242 return m;
243 }
244
pingping-lina2cbfad2013-03-07 08:39:21 +0800245 @Override
246 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700247 Collection<Class<? extends IFloodlightService>> l
248 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800249 l.add(IFloodlightProviderService.class);
250 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700251 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800252 return l;
253 }
254
255 @Override
256 public void init(FloodlightModuleContext context)
257 throws FloodlightModuleException {
258
Jonathan Hart29b972d2013-08-12 23:43:51 +1200259 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200260 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200261
262 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200263
pingping-lina2cbfad2013-03-07 08:39:21 +0800264 // Register floodlight provider and REST handler.
265 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700266 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200267 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200268 restApi = context.getServiceImpl(IRestApiService.class);
269
270 //TODO We'll initialise this here for now, but it should really be done as
271 //part of the controller core
Jonathan Harta8887642013-10-28 13:46:54 -0700272 //proxyArp = new ProxyArpManager(floodlightProvider, topologyService, this, restApi);
Jonathan Hart7e466b32013-11-04 16:31:48 -0800273 proxyArp = new BgpProxyArpManager();
274 proxyArp.init(floodlightProvider, topologyService, this, restApi);
275 //proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800276
Jonathan Hart98957bf2013-07-01 14:49:24 +1200277 linkUpdates = new ArrayList<LDUpdate>();
278 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
279 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700280
yoshif7424e42013-11-25 22:07:40 -0800281 topologyNetService = new TopologyManager(context);
Jonathan Hart98957bf2013-07-01 14:49:24 +1200282
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200283 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200284 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
285 HashMultimap.<InetAddress, RibUpdate>create());
286
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200287 pushedPaths = new HashMap<InetAddress, Path>();
288 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200289 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
290
Jonathan Hart1912afc2013-10-11 12:02:44 +1300291 flowCache = new FlowCache(floodlightProvider);
292
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200293 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
294 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
295
Jonathan Hart61ba9372013-05-19 20:10:29 -0700296 //Read in config values
297 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
298 if (bgpdRestIp == null){
299 log.error("BgpdRestIp property not found in config file");
300 System.exit(1);
301 }
302 else {
303 log.info("BgpdRestIp set to {}", bgpdRestIp);
304 }
305
306 routerId = context.getConfigParams(this).get("RouterId");
307 if (routerId == null){
308 log.error("RouterId property not found in config file");
309 System.exit(1);
310 }
311 else {
312 log.info("RouterId set to {}", routerId);
313 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200314
Jonathan Hart9575cb62013-07-05 13:43:49 +1200315 String configFilenameParameter = context.getConfigParams(this).get("configfile");
316 if (configFilenameParameter != null){
317 configFilename = configFilenameParameter;
318 }
319 log.debug("Config file set to {}", configFilename);
320
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700321 readConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200322 }
323
324 @Override
325 public void startUp(FloodlightModuleContext context) {
326 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700327 topologyService.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200328 floodlightProvider.addOFSwitchListener(this);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200329
Jonathan Hart7e466b32013-11-04 16:31:48 -0800330 proxyArp.startUp();
Jonathan Hart2f790d22013-08-15 14:01:24 +1200331
Jonathan Harta8887642013-10-28 13:46:54 -0700332 //floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200333
334 //Retrieve the RIB from BGPd during startup
335 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800336 }
337
Jonathan Hart29b972d2013-08-12 23:43:51 +1200338 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800339 return ptree;
340 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700341
342 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200343 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800344 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700345
pingping-line2a09ca2013-03-23 09:33:58 +0800346 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700347 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800348 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700349
pingping-line2a09ca2013-03-23 09:33:58 +0800350 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700351 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800352 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800353
Jonathan Hart61ba9372013-05-19 20:10:29 -0700354 private void retrieveRib(){
355 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
356 String response = RestClient.get(url);
357
358 if (response.equals("")){
359 return;
360 }
361
362 response = response.replaceAll("\"", "'");
363 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
364 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
365 String router_id = jsonObj.getString("router-id");
366
367 int size = rib_json_array.size();
368
369 log.info("Retrived RIB of {} entries from BGPd", size);
370
371 for (int j = 0; j < size; j++) {
372 JSONObject second_json_object = rib_json_array.getJSONObject(j);
373 String prefix = second_json_object.getString("prefix");
374 String nexthop = second_json_object.getString("nexthop");
375
376 //insert each rib entry into the local rib;
377 String[] substring = prefix.split("/");
378 String prefix1 = substring[0];
379 String mask1 = substring[1];
380
381 Prefix p;
382 try {
383 p = new Prefix(prefix1, Integer.valueOf(mask1));
384 } catch (NumberFormatException e) {
385 log.warn("Wrong mask format in RIB JSON: {}", mask1);
386 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200387 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700388 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
389 continue;
390 }
391
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200392 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200393
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200394 try {
395 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
396 } catch (InterruptedException e) {
397 log.debug("Interrupted while pushing onto update queue");
398 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700399 }
400 }
401
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200402 @Override
403 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200404 try {
405 ribUpdates.put(update);
406 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200407 log.debug("Interrupted while putting on ribUpdates queue", e);
408 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200409 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200410 }
411
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200412 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200413 Prefix prefix = update.getPrefix();
414
Jonathan Hart9ea31212013-08-12 21:40:34 +1200415 log.debug("Processing prefix add {}", prefix);
416
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200417 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200418
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200419 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200420 //There was an existing nexthop for this prefix. This update supersedes that,
421 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200422 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200423 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200424
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200425 if (update.getRibEntry().getNextHop().equals(
426 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200427 //Route originated by SDN domain
428 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200429 log.debug("Own route {} to {}", prefix,
430 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200431 return;
432 }
433
434 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200435 }
436
Jonathan Hart309889c2013-08-13 23:26:24 +1200437 private void _processRibAdd(RibUpdate update) {
438 Prefix prefix = update.getPrefix();
439 RibEntry rib = update.getRibEntry();
440
441 InetAddress dstIpAddress = rib.getNextHop();
442
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200443 //See if we know the MAC address of the next hop
Jonathan Hartabad6a52013-09-30 18:17:21 +1300444 MACAddress nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200445
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200446 //Find the attachment point (egress interface) of the next hop
447 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200448 if (bgpPeers.containsKey(dstIpAddress)) {
449 //Route to a peer
450 log.debug("Route to peer {}", dstIpAddress);
451 BgpPeer peer = bgpPeers.get(dstIpAddress);
452 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200453 }
454 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200455 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200456 log.debug("Route to non-peer {}", dstIpAddress);
457 egressInterface = interfacePtrie.match(
458 new Prefix(dstIpAddress.getAddress(), 32));
459 if (egressInterface == null) {
460 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
461 return;
462 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200463 }
464
465 if (nextHopMacAddress == null) {
466 prefixesWaitingOnArp.put(dstIpAddress,
467 new RibUpdate(Operation.UPDATE, prefix, rib));
468 proxyArp.sendArpRequest(dstIpAddress, this, true);
469 return;
470 }
471 else {
472 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200473 //If the prefix is for a non-peer we need to ensure there's a path,
474 //and push one if there isn't.
475 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200476 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200477 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300478 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200479 pushedPaths.put(dstIpAddress, path);
480 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200481
482 path.incrementUsers();
483 prefixToPath.put(prefix, path);
484 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200485
486 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200487 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
488 }
489 }
490
Jonathan Hartabad6a52013-09-30 18:17:21 +1300491 private void addPrefixFlows(Prefix prefix, Interface egressInterface, MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700492 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300493 prefix, nextHopMacAddress);
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200494
495 //We only need one flow mod per switch, so pick one interface on each switch
496 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
497 for (Interface intf : interfaces.values()) {
498 if (!srcInterfaces.containsKey(intf.getDpid())
Jonathan Hart45107222013-10-22 17:35:04 -0700499 && !intf.equals(egressInterface)) {
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200500 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200501 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200502 }
503
504 //Add a flow to rewrite mac for this prefix to all other border switches
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200505 for (Interface srcInterface : srcInterfaces.values()) {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200506 DataPath shortestPath;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700507 if (topology == null) {
508 shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200509 srcInterface.getSwitchPort(),
510 egressInterface.getSwitchPort());
511 }
512 else {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700513 shortestPath = topologyNetService.getTopologyShortestPath(
514 topology, srcInterface.getSwitchPort(),
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200515 egressInterface.getSwitchPort());
516 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200517
518 if (shortestPath == null){
519 log.debug("Shortest path between {} and {} not found",
520 srcInterface.getSwitchPort(),
521 egressInterface.getSwitchPort());
522 return; // just quit here?
523 }
524
525 //Set up the flow mod
526 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
527 .getMessage(OFType.FLOW_MOD);
528
529 fm.setIdleTimeout((short)0)
530 .setHardTimeout((short)0)
531 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
532 .setCookie(MAC_RW_COOKIE)
533 .setCommand(OFFlowMod.OFPFC_ADD)
534 .setPriority(SDNIP_PRIORITY)
535 .setLengthU(OFFlowMod.MINIMUM_LENGTH
536 + OFActionDataLayerDestination.MINIMUM_LENGTH
537 + OFActionOutput.MINIMUM_LENGTH);
538
539 OFMatch match = new OFMatch();
540 match.setDataLayerType(Ethernet.TYPE_IPv4);
541 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
542
543 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
544 fm.setMatch(match);
545
546 //Set up MAC rewrite action
547 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartabad6a52013-09-30 18:17:21 +1300548 macRewriteAction.setDataLayerAddress(nextHopMacAddress.toBytes());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200549
550 //Set up output action
551 OFActionOutput outputAction = new OFActionOutput();
552 outputAction.setMaxLength((short)0xffff);
553 Port outputPort = shortestPath.flowEntries().get(0).outPort();
554 outputAction.setPort(outputPort.value());
555
556 List<OFAction> actions = new ArrayList<OFAction>();
557 actions.add(macRewriteAction);
558 actions.add(outputAction);
559 fm.setActions(actions);
560
Jonathan Hart1912afc2013-10-11 12:02:44 +1300561 pushedFlows.put(prefix, new PushedFlowMod(srcInterface.getDpid(), fm));
562 flowCache.write(srcInterface.getDpid(), fm);
563
564 /*
565 * XXX Rate limit hack!
566 * This should be solved properly by adding a rate limiting
567 * layer on top of the switches if we know they need it.
568 */
569 try {
Jonathan Hart9971e1c2013-09-17 10:47:40 +1200570 Thread.sleep(1);
Jonathan Hart65139e42013-09-13 16:52:25 +1200571 } catch (InterruptedException e) {
572 // TODO handle this properly
573 log.error("Interrupted", e);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200574 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200575 }
576 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200577
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200578 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200579 Prefix prefix = update.getPrefix();
580
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200581 if (ptree.remove(prefix, update.getRibEntry())) {
582 /*
583 * Only delete flows if an entry was actually removed from the trie.
584 * If no entry was removed, the <prefix, nexthop> wasn't there so
585 * it's probably already been removed and we don't need to do anything
586 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200587 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200588 }
589 }
590
591 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
592 deletePrefixFlows(prefix);
593
594 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200595
Jonathan Hart309889c2013-08-13 23:26:24 +1200596 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
597 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200598 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200599
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200600 if (path != null) {
601 //path could be null if we added to the Ptree but didn't push
602 //flows yet because we were waiting to resolve ARP
Jonathan Hart309889c2013-08-13 23:26:24 +1200603
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200604 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200605 if (path.getUsers() <= 0 && !path.isPermanent()) {
606 deletePath(path);
607 pushedPaths.remove(path.getDstIpAddress());
608 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200609 }
610 }
611 }
612
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200613 private void deletePrefixFlows(Prefix prefix) {
614 log.debug("Deleting flows for prefix {}", prefix);
615
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200616 Collection<PushedFlowMod> pushedFlowMods
617 = pushedFlows.removeAll(prefix);
618
619 for (PushedFlowMod pfm : pushedFlowMods) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200620 if (log.isTraceEnabled()) {
621 log.trace("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
622 new Object[] {HexString.toHexString(pfm.getDpid()),
623 pfm.getFlowMod().getMatch().getNetworkDestination() +
624 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
625 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
626 .getDataLayerAddress())});
627 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200628
629 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
630 }
631 }
632
633 private void deletePath(Path path) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200634 log.debug("Deleting flows for path to {}",
635 path.getDstIpAddress().getHostAddress());
636
Jonathan Hart309889c2013-08-13 23:26:24 +1200637 for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200638 if (log.isTraceEnabled()) {
639 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
640 new Object[] {HexString.toHexString(pfm.getDpid()),
641 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
642 });
643 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200644
645 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
646 }
647 }
648
649 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
Jonathan Hart1912afc2013-10-11 12:02:44 +1300650 flowCache.delete(dpid, addFlowMod);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200651 }
652
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200653 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200654 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200655
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700656 /*
657 * On startup we need to calculate a full mesh of paths between all gateway
658 * switches
659 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200660 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700661 //For each border router, calculate and install a path from every other
662 //border switch to said border router. However, don't install the entry
663 //in to the first hop switch, as we need to install an entry to rewrite
664 //for each prefix received. This will be done later when prefixes have
665 //actually been received.
666
Jonathan Hartc824ad02013-07-03 15:58:45 +1200667 for (BgpPeer peer : bgpPeers.values()) {
668 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200669
Jonathan Hart309889c2013-08-13 23:26:24 +1200670 //We know there's not already a Path here pushed, because this is
671 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200672 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200673 path.setPermanent();
674
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200675 //See if we know the MAC address of the peer. If not we can't
676 //do anything until we learn it
Jonathan Hartabad6a52013-09-30 18:17:21 +1300677 MACAddress macAddress = proxyArp.getMacAddress(peer.getIpAddress());
678 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200679 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
680 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200681 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700682
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200683 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
684 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700685 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200686
687 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300688 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700689 }
690 }
691
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200692 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200693 Interface dstInterface = path.getDstInterface();
694
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200695 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
696 dstMacAddress);
697
Jonathan Hart309889c2013-08-13 23:26:24 +1200698 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
699
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200700 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -0700701 if (dstInterface.equals(srcInterface)){
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200702 continue;
703 }
704
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200705 DataPath shortestPath;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700706 if (topology == null) {
707 shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200708 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
709 }
710 else {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700711 shortestPath = topologyNetService.getTopologyShortestPath(topology,
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200712 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
713 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200714
715 if (shortestPath == null){
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200716 log.warn("Shortest path between {} and {} not found",
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200717 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200718 return;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200719 }
720
Jonathan Hart1912afc2013-10-11 12:02:44 +1300721 List<PushedFlowMod> pushedFlowMods = installPath(shortestPath.flowEntries(), dstMacAddress);
722 pushedFlows.addAll(pushedFlowMods);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200723 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200724
725 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200726 }
727
Jonathan Hart309889c2013-08-13 23:26:24 +1200728 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
729 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
730
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700731 //Set up the flow mod
732 OFFlowMod fm =
733 (OFFlowMod) floodlightProvider.getOFMessageFactory()
734 .getMessage(OFType.FLOW_MOD);
735
736 OFActionOutput action = new OFActionOutput();
737 action.setMaxLength((short)0xffff);
738 List<OFAction> actions = new ArrayList<OFAction>();
739 actions.add(action);
740
741 fm.setIdleTimeout((short)0)
742 .setHardTimeout((short)0)
743 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
744 .setCookie(L2_FWD_COOKIE)
745 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hartbdc87462013-09-24 15:03:23 +1200746 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700747 .setActions(actions)
748 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
749
750 //Don't push the first flow entry. We need to push entries in the
751 //first switch based on IP prefix which we don't know yet.
752 for (int i = 1; i < flowEntries.size(); i++){
753 FlowEntry flowEntry = flowEntries.get(i);
754
755 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200756 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700757 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
758 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
759
760 fm.setMatch(match);
761
Jonathan Hart1912afc2013-10-11 12:02:44 +1300762 flowMods.add(new PushedFlowMod(flowEntry.dpid().value(), fm));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700763
Jonathan Hart1912afc2013-10-11 12:02:44 +1300764 flowCache.write(flowEntry.dpid().value(), fm);
765
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700766 try {
767 fm = fm.clone();
768 } catch (CloneNotSupportedException e1) {
769 log.error("Failure cloning flow mod", e1);
770 }
771 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200772
773 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700774 }
775
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200776 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200777 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200778 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
779
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700780 DataPath path = topologyNetService.getDatabaseShortestPath(
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200781 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
782
783 if (path == null){
784 log.debug("Unable to compute path for BGP traffic for {}",
785 bgpPeer.getIpAddress());
786 continue;
787 }
788
789 //Set up the flow mod
790 OFFlowMod fm =
791 (OFFlowMod) floodlightProvider.getOFMessageFactory()
792 .getMessage(OFType.FLOW_MOD);
793
794 OFActionOutput action = new OFActionOutput();
795 action.setMaxLength((short)0xffff);
796 List<OFAction> actions = new ArrayList<OFAction>();
797 actions.add(action);
798
799 fm.setIdleTimeout((short)0)
800 .setHardTimeout((short)0)
801 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
802 .setCookie(BGP_COOKIE)
803 .setCommand(OFFlowMod.OFPFC_ADD)
804 .setPriority(SDNIP_PRIORITY)
805 .setActions(actions)
806 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
807
808 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
809 OFMatch forwardMatchSrc = new OFMatch();
810
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200811 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
812 + "/32";
813 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
814 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200815
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200816 //Common match fields
817 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200818 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300819 //forwardMatchSrc.setTransportDestination(BGP_PORT);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200820 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
821 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
822
823
824 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
825
826 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
827 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
828
829 OFMatch forwardMatchDst = forwardMatchSrc.clone();
830
831 forwardMatchSrc.setTransportSource(BGP_PORT);
832 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
833 forwardMatchDst.setTransportDestination(BGP_PORT);
834 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
835
836 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
837 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
838
839 OFMatch reverseMatchDst = reverseMatchSrc.clone();
840
841 reverseMatchSrc.setTransportSource(BGP_PORT);
842 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
843 reverseMatchDst.setTransportDestination(BGP_PORT);
844 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
845
846 fm.setMatch(forwardMatchSrc);
847
Jonathan Hart38c84932013-08-10 17:49:27 +1200848 OFMatch forwardIcmpMatch = new OFMatch();
849 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
850 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
851 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
852 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
853
854 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
855 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
856 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
857
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200858 for (FlowEntry flowEntry : path.flowEntries()){
859 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
860 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200861 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200862 try {
863 forwardFlowModSrc = fm.clone();
864 forwardFlowModDst = fm.clone();
865 reverseFlowModSrc = fm.clone();
866 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200867 forwardIcmp = fm.clone();
868 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200869 } catch (CloneNotSupportedException e) {
870 log.warn("Clone failed", e);
871 continue;
872 }
873
874 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
875 forwardFlowModSrc.setMatch(forwardMatchSrc);
876 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
877 .setPort(flowEntry.outPort().value());
878
879 forwardMatchDst.setInputPort(flowEntry.inPort().value());
880 forwardFlowModDst.setMatch(forwardMatchDst);
881 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
882 .setPort(flowEntry.outPort().value());
883
884 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
885 reverseFlowModSrc.setMatch(reverseMatchSrc);
886 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
887 .setPort(flowEntry.inPort().value());
888
889 reverseMatchDst.setInputPort(flowEntry.outPort().value());
890 reverseFlowModDst.setMatch(reverseMatchDst);
891 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
892 .setPort(flowEntry.inPort().value());
893
Jonathan Hart38c84932013-08-10 17:49:27 +1200894 ((OFActionOutput)forwardIcmp.getActions().get(0))
895 .setPort(flowEntry.outPort().value());
896 forwardIcmp.setMatch(forwardIcmpMatch);
897
898 ((OFActionOutput)reverseIcmp.getActions().get(0))
899 .setPort(flowEntry.inPort().value());
900 reverseIcmp.setMatch(reverseIcmpMatch);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200901
Jonathan Hart1912afc2013-10-11 12:02:44 +1300902 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(6);
903 flowModList.add(forwardFlowModSrc);
904 flowModList.add(forwardFlowModDst);
905 flowModList.add(reverseFlowModSrc);
906 flowModList.add(reverseFlowModDst);
907 flowModList.add(forwardIcmp);
908 flowModList.add(reverseIcmp);
909 flowCache.write(flowEntry.dpid().value(), flowModList);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200910 }
911 }
912 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200913
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200914 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +1300915 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
916 log.debug("Received ARP response: {} => {}",
917 ipAddress.getHostAddress(), macAddress);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200918
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200919 /*
920 * We synchronize on this to prevent changes to the ptree while we're pushing
921 * flows to the switches. If the ptree changes, the ptree and switches
922 * could get out of sync.
923 */
924 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200925 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200926
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200927 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200928 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300929 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200930 path.getDstInterface().getSwitchPort()});
931 //These paths should always be to BGP peers. Paths to non-peers are
932 //handled once the first prefix is ready to push
933 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200934 //A path already got pushed to this endpoint while we were waiting
935 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200936 if (path.isPermanent()) {
937 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200938 }
939 }
940 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300941 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200942 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200943 }
944 }
945
Jonathan Hart309889c2013-08-13 23:26:24 +1200946 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
947
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200948 for (RibUpdate update : prefixesToPush) {
949 //These will always be adds
950
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200951 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200952 if (rib != null && rib.equals(update.getRibEntry())) {
953 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200954 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200955 //We only push prefix flows if the prefix is still in the ptree
956 //and the next hop is the same as our update. The prefix could
957 //have been removed while we were waiting for the ARP, or the
958 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200959 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200960 } else {
961 log.debug("Received ARP response, but {},{} is no longer in ptree",
962 update.getPrefix(), update.getRibEntry());
963 }
964 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200965 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200966 }
967
Jonathan Hartc82051c2013-08-24 15:12:20 +1200968 private void setupArpFlows() {
969 OFMatch match = new OFMatch();
970 match.setDataLayerType(Ethernet.TYPE_ARP);
971 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
972
973 OFFlowMod fm = new OFFlowMod();
974 fm.setMatch(match);
975
976 OFActionOutput action = new OFActionOutput();
977 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
978 action.setMaxLength((short)0xffff);
979 List<OFAction> actions = new ArrayList<OFAction>(1);
980 actions.add(action);
981 fm.setActions(actions);
982
983 fm.setIdleTimeout((short)0)
984 .setHardTimeout((short)0)
985 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
986 .setCookie(0)
987 .setCommand(OFFlowMod.OFPFC_ADD)
988 .setPriority(ARP_PRIORITY)
989 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
990
991 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +1300992 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +1200993 }
994 }
995
Jonathan Hartf886fa12013-09-18 14:46:29 +1200996 private void setupDefaultDropFlows() {
997 OFFlowMod fm = new OFFlowMod();
998 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +1200999 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Jonathan Hartf886fa12013-09-18 14:46:29 +12001000
1001 fm.setIdleTimeout((short)0)
1002 .setHardTimeout((short)0)
1003 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1004 .setCookie(0)
1005 .setCommand(OFFlowMod.OFPFC_ADD)
1006 .setPriority((short)0)
1007 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
1008
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001009 OFFlowMod fmLLDP;
1010 OFFlowMod fmBDDP;
1011 try {
1012 fmLLDP = fm.clone();
1013 fmBDDP = fm.clone();
1014 } catch (CloneNotSupportedException e1) {
1015 log.error("Error cloning flow mod", e1);
1016 return;
1017 }
1018
1019 OFMatch matchLLDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001020 matchLLDP.setDataLayerType((short)0x88cc);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001021 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1022 fmLLDP.setMatch(matchLLDP);
1023
1024 OFMatch matchBDDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001025 matchBDDP.setDataLayerType((short)0x8942);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001026 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1027 fmBDDP.setMatch(matchBDDP);
1028
1029 OFActionOutput action = new OFActionOutput();
1030 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1031 action.setMaxLength((short)0xffff);
1032 List<OFAction> actions = new ArrayList<OFAction>(1);
1033 actions.add(action);
1034
1035 fmLLDP.setActions(actions);
1036 fmBDDP.setActions(actions);
1037
1038 fmLLDP.setPriority(ARP_PRIORITY);
1039 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1040 fmBDDP.setPriority(ARP_PRIORITY);
1041 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1042
Jonathan Hart1912afc2013-10-11 12:02:44 +13001043 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1044 flowModList.add(fm);
1045 flowModList.add(fmLLDP);
1046 flowModList.add(fmBDDP);
1047
Jonathan Hartf886fa12013-09-18 14:46:29 +12001048 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001049 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001050 }
1051 }
1052
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001053 private void beginRouting(){
1054 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001055 topology = topologyNetService.newDatabaseTopology();
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001056
Jonathan Hartc82051c2013-08-24 15:12:20 +12001057 setupArpFlows();
Jonathan Hartf886fa12013-09-18 14:46:29 +12001058 setupDefaultDropFlows();
Jonathan Hartc82051c2013-08-24 15:12:20 +12001059
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001060 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001061 setupFullMesh();
Jonathan Harte7694532013-09-12 12:34:46 +12001062
1063 //Suppress link discovery on external-facing router ports
1064 for (Interface intf : interfaces.values()) {
1065 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1066 }
1067
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001068 bgpUpdatesExecutor.execute(new Runnable() {
1069 @Override
1070 public void run() {
1071 doUpdatesThread();
1072 }
1073 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001074 }
1075
1076 private void checkSwitchesConnected(){
1077 for (String dpid : switches){
1078 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1079 log.debug("Not all switches are here yet");
1080 return;
1081 }
1082 }
1083 switchesConnected = true;
1084 }
1085
Jonathan Hartc824ad02013-07-03 15:58:45 +12001086 //Actually we only need to go half way round to verify full mesh connectivity
1087 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001088 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001089 for (Interface dstInterface : interfaces.values()) {
1090 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -07001091 if (dstInterface.equals(srcInterface)) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001092 continue;
1093 }
1094
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001095 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001096 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001097
1098 if (shortestPath == null){
1099 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001100 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001101 return;
1102 }
1103 }
1104 }
1105 topologyReady = true;
1106 }
1107
1108 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001109 if (!switchesConnected){
1110 checkSwitchesConnected();
1111 }
1112 boolean oldTopologyReadyStatus = topologyReady;
1113 if (switchesConnected && !topologyReady){
1114 checkTopologyReady();
1115 }
1116 if (!oldTopologyReadyStatus && topologyReady){
1117 beginRouting();
1118 }
1119 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001120
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001121 private void doUpdatesThread() {
1122 boolean interrupted = false;
1123 try {
1124 while (true) {
1125 try {
1126 RibUpdate update = ribUpdates.take();
1127 switch (update.getOperation()){
1128 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001129 if (validateUpdate(update)) {
1130 processRibAdd(update);
1131 }
1132 else {
1133 log.debug("Rib UPDATE out of order: {} via {}",
1134 update.getPrefix(), update.getRibEntry().getNextHop());
1135 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001136 break;
1137 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001138 if (validateUpdate(update)) {
1139 processRibDelete(update);
1140 }
1141 else {
1142 log.debug("Rib DELETE out of order: {} via {}",
1143 update.getPrefix(), update.getRibEntry().getNextHop());
1144 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001145 break;
1146 }
1147 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001148 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001149 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001150 } catch (Exception e) {
1151 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001152 }
1153 }
1154 } finally {
1155 if (interrupted) {
1156 Thread.currentThread().interrupt();
1157 }
1158 }
1159 }
Jonathan Harte4c98692013-10-18 17:40:03 -07001160
1161 private boolean validateUpdate(RibUpdate update) {
1162 RibEntry newEntry = update.getRibEntry();
1163 RibEntry oldEntry = ptree.lookup(update.getPrefix());
1164
1165 //If there is no existing entry we must assume this is the most recent
1166 //update. However this might not always be the case as we might have a
1167 //POST then DELETE reordering.
1168 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1169 if (oldEntry == null) {
1170 return true;
1171 }
1172
1173 // This handles the case where routes are gathered in the initial
1174 // request because they don't have sequence number info
1175 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1176 return true;
1177 }
1178
1179 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1180 return true;
1181 }
1182 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1183 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1184 return true;
1185 }
1186 else {
1187 return false;
1188 }
1189 }
1190 else {
1191 return false;
1192 }
1193 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001194
1195 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001196 public void topologyChanged() {
1197 if (topologyReady) {
1198 return;
1199 }
1200
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001201 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001202 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001203 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1204 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001205 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001206 refreshNeeded = true;
1207 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001208
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001209 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001210
Jonathan Hart98957bf2013-07-01 14:49:24 +12001211 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1212 synchronized (linkUpdates) {
1213 linkUpdates.add(ldu);
1214 }
1215 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001216 }
1217
Jonathan Hart64c0b202013-08-20 15:45:07 +12001218 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001219 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001220 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001221 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001222
1223 @Override
1224 public void addedSwitch(IOFSwitch sw) {
1225 if (!topologyReady) {
1226 sw.clearAllFlowMods();
1227 }
Jonathan Hart1912afc2013-10-11 12:02:44 +13001228
1229 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001230 }
1231
1232 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001233 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001234
1235 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001236 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001237
1238 @Override
1239 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001240 return "BgpRoute";
1241 }
1242
1243 /*
Jonathan Harta8887642013-10-28 13:46:54 -07001244 * IConfigInfoService methods
Jonathan Hart08ee8522013-09-22 17:34:43 +12001245 */
1246
1247 @Override
1248 public boolean isInterfaceAddress(InetAddress address) {
1249 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1250 return (intf != null && intf.getIpAddress().equals(address));
1251 }
1252
1253 @Override
1254 public boolean inConnectedNetwork(InetAddress address) {
1255 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1256 return (intf != null && !intf.getIpAddress().equals(address));
1257 }
1258
1259 @Override
1260 public boolean fromExternalNetwork(long inDpid, short inPort) {
1261 for (Interface intf : interfaces.values()) {
1262 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1263 return true;
1264 }
1265 }
1266 return false;
1267 }
1268
1269 @Override
1270 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1271 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1272 }
1273
1274 @Override
1275 public boolean hasLayer3Configuration() {
1276 return !interfaces.isEmpty();
1277 }
1278
1279 @Override
1280 public MACAddress getRouterMacAddress() {
1281 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001282 }
Jonathan Harta8887642013-10-28 13:46:54 -07001283
1284 @Override
1285 public short getVlan() {
1286 return vlan;
1287 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001288}