blob: 1363c199c74ac84d234a56e49857b163421342e0 [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-linba5c52f2014-02-11 16:52:01 -08006import java.net.UnknownHostException;
pingping-lina2cbfad2013-03-07 08:39:21 +08007import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07008import java.util.Collection;
pingping-lina2cbfad2013-03-07 08:39:21 +08009import java.util.HashMap;
Jonathan Hart98957bf2013-07-01 14:49:24 +120010import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070011import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070012import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120013import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120014import java.util.concurrent.BlockingQueue;
15import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120016import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120017import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120018import java.util.concurrent.ScheduledExecutorService;
19import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080020
Jonathan Hart61ba9372013-05-19 20:10:29 -070021import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070022import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart64c0b202013-08-20 15:45:07 +120023import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080024import net.floodlightcontroller.core.module.FloodlightModuleContext;
25import net.floodlightcontroller.core.module.FloodlightModuleException;
26import net.floodlightcontroller.core.module.IFloodlightModule;
27import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120028import net.floodlightcontroller.core.util.SingletonTask;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070029import net.floodlightcontroller.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120030import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080031import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120032import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080033import net.floodlightcontroller.topology.ITopologyListener;
34import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120035import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120036import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
pingping-linba5c52f2014-02-11 16:52:01 -080037import net.onrc.onos.ofcontroller.core.IDeviceStorage;
38import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
39import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
Jonathan Hart98957bf2013-07-01 14:49:24 +120040import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
pingping-linba5c52f2014-02-11 16:52:01 -080041import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoSwitchService;
Jonathan Hartebba1e12013-10-29 11:37:02 -070042import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
pingping-linba5c52f2014-02-11 16:52:01 -080043import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
Jonathan Hart98957bf2013-07-01 14:49:24 +120044import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
pingping-linba5c52f2014-02-11 16:52:01 -080045import net.onrc.onos.ofcontroller.core.internal.TopoSwitchServiceImpl;
46import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070047import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
48import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harte7694532013-09-12 12:34:46 +120049import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120050import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
pingping-linba5c52f2014-02-11 16:52:01 -080051import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070052import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070053import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070054import net.onrc.onos.ofcontroller.topology.TopologyManager;
pingping-linba5c52f2014-02-11 16:52:01 -080055import net.onrc.onos.ofcontroller.util.CallerId;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070056import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120057import net.onrc.onos.ofcontroller.util.Dpid;
pingping-linba5c52f2014-02-11 16:52:01 -080058import net.onrc.onos.ofcontroller.util.FlowEntryAction;
59import net.onrc.onos.ofcontroller.util.FlowEntryActions;
60import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
61import net.onrc.onos.ofcontroller.util.FlowId;
62import net.onrc.onos.ofcontroller.util.FlowPath;
63import net.onrc.onos.ofcontroller.util.FlowPathFlags;
64import net.onrc.onos.ofcontroller.util.FlowPathType;
65import net.onrc.onos.ofcontroller.util.FlowPathUserState;
66import net.onrc.onos.ofcontroller.util.IPv4Net;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070067import net.onrc.onos.ofcontroller.util.Port;
68import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080069import net.sf.json.JSONArray;
70import net.sf.json.JSONObject;
71import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080072
Jonathan Hartd1f23252013-06-13 15:17:05 +120073import org.codehaus.jackson.JsonParseException;
74import org.codehaus.jackson.map.JsonMappingException;
75import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070076import org.openflow.protocol.OFFlowMod;
77import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070078import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120079import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070080import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070081import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120082import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080083import org.slf4j.Logger;
84import org.slf4j.LoggerFactory;
85
Jonathan Hart4dfc3652013-08-02 20:22:36 +120086import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120087import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120088import com.google.common.collect.Multimaps;
89import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120090import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120091import com.google.common.util.concurrent.ThreadFactoryBuilder;
92
Jonathan Hart1236a9b2013-06-18 22:10:05 +120093public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120094 ITopologyListener, IArpRequester,
Jonathan Hart7804bea2014-01-07 10:50:52 -080095 IOFSwitchListener, IConfigInfoService {
pingping-lina2cbfad2013-03-07 08:39:21 +080096
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070097 private final static Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080098
Jonathan Hartf247ee72013-10-18 18:57:28 -070099 private IFloodlightProviderService floodlightProvider;
Jonathan Hart3a326122013-10-21 11:51:13 -0700100 private ITopologyService topologyService;
Jonathan Hartf247ee72013-10-18 18:57:28 -0700101 private ITopologyNetService topologyNetService;
102 private ILinkDiscoveryService linkDiscoveryService;
103 private IRestApiService restApi;
pingping-linba5c52f2014-02-11 16:52:01 -0800104 private IProxyArpService proxyArp;
105 protected volatile IFlowService flowManagerService;
106 private IDeviceStorage deviceStorage;
107 private ITopoSwitchService topoSwitchService;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200108
Jonathan Hartf247ee72013-10-18 18:57:28 -0700109 private IPatriciaTrie<RibEntry> ptree;
110 private IPatriciaTrie<Interface> interfacePtrie;
111 private BlockingQueue<RibUpdate> ribUpdates;
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200112
Jonathan Hartf247ee72013-10-18 18:57:28 -0700113 private String bgpdRestIp;
114 private String routerId;
115 private String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700116
117 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
118 //the controller/OS should hand out cookie IDs to prevent conflicts.
Jonathan Hartf247ee72013-10-18 18:57:28 -0700119 private final long APP_COOKIE = 0xa0000000000000L;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700120 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Jonathan Hartf247ee72013-10-18 18:57:28 -0700121 private final long L2_FWD_COOKIE = APP_COOKIE + 1;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700122 //Cookie for flows in ingress switches that rewrite the MAC address
Jonathan Hartf247ee72013-10-18 18:57:28 -0700123 private final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200124 //Cookie for flows that setup BGP paths
Jonathan Hartf247ee72013-10-18 18:57:28 -0700125 private final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200126 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
127 //need to be higher priority than this otherwise the rewrite may not get done
Jonathan Hartf247ee72013-10-18 18:57:28 -0700128 private final short SDNIP_PRIORITY = 10;
129 private final short ARP_PRIORITY = 20;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700130
Jonathan Hartf247ee72013-10-18 18:57:28 -0700131 private final short BGP_PORT = 179;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200132
Jonathan Hartf247ee72013-10-18 18:57:28 -0700133 private final int TOPO_DETECTION_WAIT = 2; //seconds
Jonathan Hart98957bf2013-07-01 14:49:24 +1200134
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200135 //Configuration stuff
Jonathan Hartf247ee72013-10-18 18:57:28 -0700136 private List<String> switches;
137 private Map<String, Interface> interfaces;
138 private Map<InetAddress, BgpPeer> bgpPeers;
139 private SwitchPort bgpdAttachmentPoint;
140 private MACAddress bgpdMacAddress;
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700141 private short vlan;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200142
143 //True when all switches have connected
Jonathan Hartf247ee72013-10-18 18:57:28 -0700144 private volatile boolean switchesConnected = false;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200145 //True when we have a full mesh of shortest paths between gateways
Jonathan Hartf247ee72013-10-18 18:57:28 -0700146 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200147
Jonathan Hartf247ee72013-10-18 18:57:28 -0700148 private ArrayList<LDUpdate> linkUpdates;
149 private SingletonTask topologyChangeDetectorTask;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200150
Jonathan Hartf247ee72013-10-18 18:57:28 -0700151 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200152
Jonathan Hartf247ee72013-10-18 18:57:28 -0700153 private Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200154
Jonathan Hartf247ee72013-10-18 18:57:28 -0700155 private ExecutorService bgpUpdatesExecutor;
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200156
Jonathan Hartf247ee72013-10-18 18:57:28 -0700157 private Map<InetAddress, Path> pushedPaths;
158 private Map<Prefix, Path> prefixToPath;
pingping-linba5c52f2014-02-11 16:52:01 -0800159// private Multimap<Prefix, PushedFlowMod> pushedFlows;
160 private Multimap<Prefix, FlowId> pushedFlowIds;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200161
Jonathan Hart1912afc2013-10-11 12:02:44 +1300162 private FlowCache flowCache;
163
Jonathan Hart3a326122013-10-21 11:51:13 -0700164 private volatile Topology topology = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800165
Jonathan Hartf247ee72013-10-18 18:57:28 -0700166 private class TopologyChangeDetector implements Runnable {
Jonathan Hart98957bf2013-07-01 14:49:24 +1200167 @Override
168 public void run() {
169 log.debug("Running topology change detection task");
170 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200171 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200172 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
173
174 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200175
176 Iterator<LDUpdate> it = linkUpdates.iterator();
177 while (it.hasNext()){
178 LDUpdate ldu = it.next();
179 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
180 ldu.getDst(), ldu.getDstPort());
181
182 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200183 it.remove();
184 }
185 }
186 }
187
Jonathan Hart64c0b202013-08-20 15:45:07 +1200188 if (!topologyReady) {
189 if (linkUpdates.isEmpty()){
190 //All updates have been seen in network map.
191 //We can check if topology is ready
192 log.debug("No known changes outstanding. Checking topology now");
193 checkStatus();
194 }
195 else {
196 //We know of some link updates that haven't propagated to the database yet
197 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
198 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
199 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200200 }
201 }
202 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700203
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700204 private void readConfiguration(String configFilename){
205 File gatewaysFile = new File(configFilename);
Jonathan Hartd1f23252013-06-13 15:17:05 +1200206 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700207
Jonathan Hartd1f23252013-06-13 15:17:05 +1200208 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200209 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
210
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200211 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200212 interfaces = new HashMap<String, Interface>();
213 for (Interface intf : config.getInterfaces()){
214 interfaces.put(intf.getName(), intf);
215 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200216 bgpPeers = new HashMap<InetAddress, BgpPeer>();
217 for (BgpPeer peer : config.getPeers()){
218 bgpPeers.put(peer.getIpAddress(), peer);
219 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200220
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200221 bgpdAttachmentPoint = new SwitchPort(
222 new Dpid(config.getBgpdAttachmentDpid()),
223 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200224
Jonathan Hart2f790d22013-08-15 14:01:24 +1200225 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700226 vlan = config.getVlan();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200227 } catch (JsonParseException e) {
228 log.error("Error in JSON file", e);
229 System.exit(1);
230 } catch (JsonMappingException e) {
231 log.error("Error in JSON file", e);
232 System.exit(1);
233 } catch (IOException e) {
234 log.error("Error reading JSON file", e);
235 System.exit(1);
236 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200237
238 //Populate the interface Patricia Trie
239 for (Interface intf : interfaces.values()) {
240 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
241 interfacePtrie.put(prefix, intf);
242 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700243 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800244
245 @Override
246 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
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(IBgpRouteService.class);
Jonathan Harta8887642013-10-28 13:46:54 -0700250 l.add(IConfigInfoService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800251 return l;
252 }
pingping-linba5c52f2014-02-11 16:52:01 -0800253
pingping-lina2cbfad2013-03-07 08:39:21 +0800254 @Override
255 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700256 Map<Class<? extends IFloodlightService>, IFloodlightService> m
257 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800258 m.put(IBgpRouteService.class, this);
Jonathan Harta8887642013-10-28 13:46:54 -0700259 m.put(IConfigInfoService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800260 return m;
261 }
262
pingping-lina2cbfad2013-03-07 08:39:21 +0800263 @Override
264 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700265 Collection<Class<? extends IFloodlightService>> l
266 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800267 l.add(IFloodlightProviderService.class);
268 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700269 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800270 return l;
271 }
272
273 @Override
274 public void init(FloodlightModuleContext context)
275 throws FloodlightModuleException {
pingping-linba5c52f2014-02-11 16:52:01 -0800276
Jonathan Hart29b972d2013-08-12 23:43:51 +1200277 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200278 interfacePtrie = new PatriciaTrie<Interface>(32);
pingping-linba5c52f2014-02-11 16:52:01 -0800279
280 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
281
pingping-lina2cbfad2013-03-07 08:39:21 +0800282 // Register floodlight provider and REST handler.
283 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700284 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200285 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200286 restApi = context.getServiceImpl(IRestApiService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800287 flowManagerService = context.getServiceImpl(IFlowService.class);
288 proxyArp = context.getServiceImpl(IProxyArpService.class);
289
290 deviceStorage = new DeviceStorageImpl();
291 deviceStorage.init("", "");
292
Jonathan Hart98957bf2013-07-01 14:49:24 +1200293 linkUpdates = new ArrayList<LDUpdate>();
294 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
295 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700296
yoshif7424e42013-11-25 22:07:40 -0800297 topologyNetService = new TopologyManager(context);
pingping-linba5c52f2014-02-11 16:52:01 -0800298 topoSwitchService = new TopoSwitchServiceImpl();
299
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200300 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200301 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
302 HashMultimap.<InetAddress, RibUpdate>create());
303
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200304 pushedPaths = new HashMap<InetAddress, Path>();
305 prefixToPath = new HashMap<Prefix, Path>();
pingping-linba5c52f2014-02-11 16:52:01 -0800306// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
307 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200308
Jonathan Hart1912afc2013-10-11 12:02:44 +1300309 flowCache = new FlowCache(floodlightProvider);
310
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200311 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
312 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
313
Jonathan Hart61ba9372013-05-19 20:10:29 -0700314 //Read in config values
315 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
316 if (bgpdRestIp == null){
317 log.error("BgpdRestIp property not found in config file");
318 System.exit(1);
319 }
320 else {
321 log.info("BgpdRestIp set to {}", bgpdRestIp);
322 }
323
324 routerId = context.getConfigParams(this).get("RouterId");
325 if (routerId == null){
326 log.error("RouterId property not found in config file");
327 System.exit(1);
328 }
329 else {
330 log.info("RouterId set to {}", routerId);
331 }
pingping-linba5c52f2014-02-11 16:52:01 -0800332
Jonathan Hart9575cb62013-07-05 13:43:49 +1200333 String configFilenameParameter = context.getConfigParams(this).get("configfile");
334 if (configFilenameParameter != null){
335 configFilename = configFilenameParameter;
336 }
337 log.debug("Config file set to {}", configFilename);
338
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700339 readConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200340 }
341
342 @Override
343 public void startUp(FloodlightModuleContext context) {
344 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700345 topologyService.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200346 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800347
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200348 //Retrieve the RIB from BGPd during startup
349 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800350 }
351
Jonathan Hart29b972d2013-08-12 23:43:51 +1200352 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800353 return ptree;
354 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700355
356 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200357 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800358 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700359
pingping-line2a09ca2013-03-23 09:33:58 +0800360 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700361 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800362 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700363
pingping-line2a09ca2013-03-23 09:33:58 +0800364 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700365 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800366 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800367
Jonathan Hart61ba9372013-05-19 20:10:29 -0700368 private void retrieveRib(){
369 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
370 String response = RestClient.get(url);
371
372 if (response.equals("")){
373 return;
374 }
375
376 response = response.replaceAll("\"", "'");
377 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
378 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
379 String router_id = jsonObj.getString("router-id");
380
381 int size = rib_json_array.size();
382
383 log.info("Retrived RIB of {} entries from BGPd", size);
384
385 for (int j = 0; j < size; j++) {
386 JSONObject second_json_object = rib_json_array.getJSONObject(j);
387 String prefix = second_json_object.getString("prefix");
388 String nexthop = second_json_object.getString("nexthop");
389
390 //insert each rib entry into the local rib;
391 String[] substring = prefix.split("/");
392 String prefix1 = substring[0];
393 String mask1 = substring[1];
394
395 Prefix p;
396 try {
397 p = new Prefix(prefix1, Integer.valueOf(mask1));
398 } catch (NumberFormatException e) {
399 log.warn("Wrong mask format in RIB JSON: {}", mask1);
400 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200401 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700402 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
403 continue;
404 }
405
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200406 RibEntry rib = new RibEntry(router_id, nexthop);
pingping-linba5c52f2014-02-11 16:52:01 -0800407
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200408 try {
409 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
410 } catch (InterruptedException e) {
411 log.debug("Interrupted while pushing onto update queue");
412 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700413 }
414 }
415
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200416 @Override
417 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200418 try {
419 ribUpdates.put(update);
420 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200421 log.debug("Interrupted while putting on ribUpdates queue", e);
422 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200423 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200424 }
425
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200426 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200427 Prefix prefix = update.getPrefix();
428
Jonathan Hart9ea31212013-08-12 21:40:34 +1200429 log.debug("Processing prefix add {}", prefix);
430
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200431 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200432
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200433 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200434 //There was an existing nexthop for this prefix. This update supersedes that,
435 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200436 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200437 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200438
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200439 if (update.getRibEntry().getNextHop().equals(
440 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200441 //Route originated by SDN domain
442 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200443 log.debug("Own route {} to {}", prefix,
444 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200445 return;
446 }
447
448 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200449 }
450
Jonathan Hart309889c2013-08-13 23:26:24 +1200451 private void _processRibAdd(RibUpdate update) {
452 Prefix prefix = update.getPrefix();
453 RibEntry rib = update.getRibEntry();
454
455 InetAddress dstIpAddress = rib.getNextHop();
pingping-linba5c52f2014-02-11 16:52:01 -0800456 MACAddress nextHopMacAddress;
457
458 // See if we know the MAC address of the next hop
459 // TODO if we do not treat the next hop as a device in the future, we need to update this
460 IDeviceObject nextHopDevice =
461 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Jonathan Hart309889c2013-08-13 23:26:24 +1200462
pingping-linba5c52f2014-02-11 16:52:01 -0800463 if (nextHopDevice == null){
464 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
465 prefixesWaitingOnArp.put(dstIpAddress,
466 new RibUpdate(Operation.UPDATE, prefix, rib));
467 proxyArp.sendArpRequest(dstIpAddress, this, true);
468 return;
469
470 }
471 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200472
pingping-linba5c52f2014-02-11 16:52:01 -0800473 // Find the attachment point (egress interface) of the next hop
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200474 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200475 if (bgpPeers.containsKey(dstIpAddress)) {
476 //Route to a peer
477 log.debug("Route to peer {}", dstIpAddress);
478 BgpPeer peer = bgpPeers.get(dstIpAddress);
479 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200480 }
481 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200482 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200483 log.debug("Route to non-peer {}", dstIpAddress);
484 egressInterface = interfacePtrie.match(
485 new Prefix(dstIpAddress.getAddress(), 32));
486 if (egressInterface == null) {
487 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
488 return;
489 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200490 }
491
492 if (nextHopMacAddress == null) {
493 prefixesWaitingOnArp.put(dstIpAddress,
494 new RibUpdate(Operation.UPDATE, prefix, rib));
495 proxyArp.sendArpRequest(dstIpAddress, this, true);
496 return;
497 }
498 else {
499 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200500 //If the prefix is for a non-peer we need to ensure there's a path,
501 //and push one if there isn't.
502 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200503 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200504 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300505 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200506 pushedPaths.put(dstIpAddress, path);
507 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200508
509 path.incrementUsers();
510 prefixToPath.put(prefix, path);
511 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200512
513 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200514 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
515 }
516 }
517
pingping-linba5c52f2014-02-11 16:52:01 -0800518 /**
519 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
520 * to all other border switches
521 */
522 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
523 MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700524 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300525 prefix, nextHopMacAddress);
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200526
pingping-linba5c52f2014-02-11 16:52:01 -0800527 FlowPath flowPath = new FlowPath();
528 flowPath.setInstallerId(new CallerId("SDNIP"));
529
530 // Set flowPath FlowPathType and FlowPathUserState
531 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
532 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
533
534 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
535 // only to the first-host switches
536 FlowPathFlags flowPathFlags = new FlowPathFlags();
537 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
538 flowPath.setFlowPathFlags(flowPathFlags);
539
540 // Create the DataPath object: dstSwitchPort
541 SwitchPort dstPort = new SwitchPort();
542 dstPort.setDpid(new Dpid(egressInterface.getDpid()));
543 dstPort.setPort(new Port(egressInterface.getPort()));
544
545 // We only need one flow mod per switch, so pick one interface on each switch
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200546 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
547 for (Interface intf : interfaces.values()) {
548 if (!srcInterfaces.containsKey(intf.getDpid())
Jonathan Hart45107222013-10-22 17:35:04 -0700549 && !intf.equals(egressInterface)) {
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200550 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200551 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200552 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200553 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800554
555 if (egressInterface.equals(srcInterface)){
556 continue;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200557 }
pingping-linba5c52f2014-02-11 16:52:01 -0800558
559 // Create flowPath FlowId
560 //FlowId returnByRefFlowId = new FlowId(flowManagerService.getNextFlowEntryId());
561 //flowPath.setFlowId(returnByRefFlowId);
562 flowPath.setFlowId(new FlowId());
563
564 // Create DataPath object: srcSwitchPort
565 SwitchPort srcPort = new SwitchPort();
566 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
567 srcPort.setPort(new Port(srcInterface.getPort()));
568
569 DataPath dataPath = new DataPath();
570 dataPath.setSrcPort(srcPort);
571 dataPath.setDstPort(dstPort);
572 flowPath.setDataPath(dataPath);
573
574 // Create flow path matching condition(s): IPv4 Prefix
575 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
576 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
577 IPv4Net dstIPv4Net= new IPv4Net(prefix.toString());
578 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
579 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300580
581 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800582 * Create the Flow Entry Action(s): dst-MAC rewrite action
Jonathan Hart1912afc2013-10-11 12:02:44 +1300583 */
pingping-linba5c52f2014-02-11 16:52:01 -0800584 FlowEntryActions flowEntryActions = new FlowEntryActions();
585 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
586 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
587 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
588 flowEntryActions.addAction(flowEntryAction1);
589 flowPath.setFlowEntryActions(flowEntryActions);
590
591 // Flow Path installation, only to first hop switches
592 if (flowManagerService.addFlow(flowPath) == null) {
593 log.error("Failed to install flow path to the first hop for " +
594 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
595 nextHopMacAddress);
596 }
597 else {
598 log.debug("Successfully installed flow path to the first hop " +
599 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
600 nextHopMacAddress);
601
602 pushedFlowIds.put(prefix, flowPath.flowId());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200603 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200604 }
605 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200606
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200607 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200608 Prefix prefix = update.getPrefix();
609
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200610 if (ptree.remove(prefix, update.getRibEntry())) {
611 /*
612 * Only delete flows if an entry was actually removed from the trie.
613 * If no entry was removed, the <prefix, nexthop> wasn't there so
614 * it's probably already been removed and we don't need to do anything
615 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200616 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200617 }
618 }
619
620 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
621 deletePrefixFlows(prefix);
622
623 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200624
Jonathan Hart309889c2013-08-13 23:26:24 +1200625 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
626 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200627 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200628
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200629 if (path != null) {
630 //path could be null if we added to the Ptree but didn't push
631 //flows yet because we were waiting to resolve ARP
pingping-linba5c52f2014-02-11 16:52:01 -0800632
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200633 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200634 if (path.getUsers() <= 0 && !path.isPermanent()) {
635 deletePath(path);
636 pushedPaths.remove(path.getDstIpAddress());
637 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200638 }
639 }
640 }
641
pingping-linba5c52f2014-02-11 16:52:01 -0800642 // TODO have not tested this module
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200643 private void deletePrefixFlows(Prefix prefix) {
644 log.debug("Deleting flows for prefix {}", prefix);
645
pingping-linba5c52f2014-02-11 16:52:01 -0800646 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
647 for (FlowId flowId : flowIds) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200648 if (log.isTraceEnabled()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800649 //Trace the flow status by flowPath in the switch before deleting it
650 log.trace("Pushing a DELETE flow mod to flowPath : {}",
651 flowManagerService.getFlow(flowId).toString());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200652 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200653
pingping-linba5c52f2014-02-11 16:52:01 -0800654 if( flowManagerService.deleteFlow(flowId))
655 {
656 log.debug("Successfully deleted FlowId: {}",flowId);
657 }
658 else
659 {
660 log.debug("Failed to delete FlowId: {}",flowId);
661 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200662 }
663 }
664
pingping-linba5c52f2014-02-11 16:52:01 -0800665 // TODO need to record the path and then delete here
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200666 private void deletePath(Path path) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200667 log.debug("Deleting flows for path to {}",
668 path.getDstIpAddress().getHostAddress());
669
pingping-linba5c52f2014-02-11 16:52:01 -0800670 // TODO need update
671 /*for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200672 if (log.isTraceEnabled()) {
673 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
674 new Object[] {HexString.toHexString(pfm.getDpid()),
675 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
676 });
677 }
pingping-linba5c52f2014-02-11 16:52:01 -0800678
Jonathan Hart309889c2013-08-13 23:26:24 +1200679 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
pingping-linba5c52f2014-02-11 16:52:01 -0800680 }*/
Jonathan Hart309889c2013-08-13 23:26:24 +1200681 }
682
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200683
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200684 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200685 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800686
687 /**
688 * On startup, we need to calculate a full mesh of paths between all gateway
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700689 * switches
690 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200691 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700692 //For each border router, calculate and install a path from every other
693 //border switch to said border router. However, don't install the entry
694 //in to the first hop switch, as we need to install an entry to rewrite
695 //for each prefix received. This will be done later when prefixes have
696 //actually been received.
697
Jonathan Hartc824ad02013-07-03 15:58:45 +1200698 for (BgpPeer peer : bgpPeers.values()) {
699 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200700
Jonathan Hart309889c2013-08-13 23:26:24 +1200701 //We know there's not already a Path here pushed, because this is
702 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200703 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200704 path.setPermanent();
705
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200706 //See if we know the MAC address of the peer. If not we can't
707 //do anything until we learn it
pingping-linba5c52f2014-02-11 16:52:01 -0800708 MACAddress macAddress;
709 IDeviceObject nextHopDevice =
710 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
711
712 if(nextHopDevice == null){
713 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
714 //Put in the pending paths list first
715 pathsWaitingOnArp.put(peer.getIpAddress(), path);
716 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
717 continue;
718 }
719
720 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
721
Jonathan Hartabad6a52013-09-30 18:17:21 +1300722 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200723 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
724 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200725 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200726 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
727 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700728 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200729
730 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300731 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700732 }
733 }
pingping-linba5c52f2014-02-11 16:52:01 -0800734
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200735 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200736 Interface dstInterface = path.getDstInterface();
737
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200738 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
739 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800740
741 FlowPath flowPath = new FlowPath();
742
743 flowPath.setInstallerId(new CallerId("SDNIP"));
744
745 // Set flowPath FlowPathType and FlowPathUserState
746 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
747 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
748
749 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
750 FlowPathFlags flowPathFlags = new FlowPathFlags();
751 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
752 flowPath.setFlowPathFlags(flowPathFlags);
753
754 // Create the DataPath object: dstSwitchPort
755 SwitchPort dstPort = new SwitchPort();
756 dstPort.setDpid(new Dpid(dstInterface.getDpid()));
757 dstPort.setPort(new Port(dstInterface.getPort()));
758
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200759 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800760
Jonathan Hart45107222013-10-22 17:35:04 -0700761 if (dstInterface.equals(srcInterface)){
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200762 continue;
763 }
pingping-linba5c52f2014-02-11 16:52:01 -0800764
765 // Create flowPath FlowId
766 //FlowId returnByRefFlowId = new FlowId(flowManagerService.getNextFlowEntryId());
767 //flowPath.setFlowId(returnByRefFlowId);
768 flowPath.setFlowId(new FlowId());
769
770 // Create the DataPath object: srcSwitchPort
771 SwitchPort srcPort = new SwitchPort();
772 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
773 srcPort.setPort(new Port(srcInterface.getPort()));
774
775 DataPath dataPath = new DataPath();
776 dataPath.setSrcPort(srcPort);
777 dataPath.setDstPort(dstPort);
778 flowPath.setDataPath(dataPath);
779
780 // Create the Flow Path Match condition(s)
781 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
782 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
783 flowEntryMatch.enableDstMac(dstMacAddress);
784 flowPath.setFlowEntryMatch(flowEntryMatch);
785
786 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
787 // Shortest Path Flow, and is always the last action for the Flow Entries
788 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
789 if (flowManagerService.addFlow(flowPath) == null) {
790 log.error("Failed to set up MAC based forwarding path to {}, {}",
791 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200792 }
793 else {
pingping-linba5c52f2014-02-11 16:52:01 -0800794 log.debug("Successfully set up MAC based forwarding path to {}, {}",
795 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200796 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200797 }
798 }
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200799
pingping-linba5c52f2014-02-11 16:52:01 -0800800 /**
801 * Pre-actively install all BGP traffic paths from BGP host attachment point
802 * in SDN network to all the virtual gateways to BGP peers in other networks
803 */
804 private void setupBgpPaths(){
805
806 for (BgpPeer bgpPeer : bgpPeers.values()){
807
808 FlowPath flowPath = new FlowPath();
809 flowPath.setInstallerId(new CallerId("SDNIP"));
810
811 // Set flowPath FlowPathType and FlowPathUserState
812 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
813 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
814
815 // Install flow paths between BGPd and its peers
816 // There is no need to set the FlowPathFlags
817 flowPath.setFlowPathFlags(new FlowPathFlags(0));
818
819 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
820
821 // set flowPath FlowId
822 //FlowId returnByRefFlowId = new FlowId(flowManagerService.getNextFlowEntryId());
823 //flowPath.setFlowId(returnByRefFlowId);
824
825
826 // Create the Flow Path Match condition(s)
827 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
828 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
829
830 // Match both source address and dest address
831 IPv4Net dstIPv4Net= new IPv4Net(bgpPeer.getIpAddress().getHostAddress()+"/32");
832 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
833
834 IPv4Net srcIPv4Net= new IPv4Net(peerInterface.getIpAddress().getHostAddress()+"/32");
835 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
836
837 // Match TCP protocol
838 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
839
840 // Match destination TCP port
841 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
842 flowPath.setFlowEntryMatch(flowEntryMatch);
843
844 /**
845 * Create the DataPath: BGP -> BGP peer
846 */
847 // Flow path for src-TCP-port
848 DataPath dataPath = new DataPath();
849
850 SwitchPort srcPort = new SwitchPort();
851 srcPort.setDpid(bgpdAttachmentPoint.dpid());
852 srcPort.setPort(bgpdAttachmentPoint.port());
853 dataPath.setSrcPort(srcPort);
854
855 SwitchPort dstPort = new SwitchPort();
856 dstPort.setDpid(new Dpid(peerInterface.getDpid()));
857 dstPort.setPort(new Port(peerInterface.getSwitchPort().port()));
858 dataPath.setDstPort(dstPort);
859
860 flowPath.setDataPath(dataPath);
861
862 if (flowManagerService.addFlow(flowPath) == null) {
863 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
864 bgpPeer.getIpAddress().getHostAddress());
865 }
866 else {
867 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
868 bgpPeer.getIpAddress().getHostAddress());
869 }
870
871 // Disable dst-TCP-port, and set src-TCP-port
872 flowEntryMatch.disableDstTcpUdpPort();
873 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
874 flowPath.setFlowEntryMatch(flowEntryMatch);
875
876 // Create a new FlowId
877 //FlowId returnByRefFlowId2 = new FlowId(flowManagerService.getNextFlowEntryId());
878 //flowPath.setFlowId(returnByRefFlowId2);
879 flowPath.setFlowId(new FlowId());
880
881 if (flowManagerService.addFlow(flowPath) == null) {
882 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
883 bgpPeer.getIpAddress().getHostAddress());
884 }
885 else {
886 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
887 bgpPeer.getIpAddress().getHostAddress());
888 }
889
890 /**
891 * Create the DataPath: BGP <-BGP peer
892 */
893 // Reversed BGP flow path for src-TCP-port
894 //FlowId returnByRefFlowId3 = new FlowId(flowManagerService.getNextFlowEntryId());
895 //flowPath.setFlowId(returnByRefFlowId3);
896 flowPath.setFlowId(new FlowId());
897
898 DataPath reverse_dataPath = new DataPath();
899
900 SwitchPort reverse_dstPort = new SwitchPort();
901 reverse_dstPort.setDpid(bgpdAttachmentPoint.dpid());
902 reverse_dstPort.setPort(bgpdAttachmentPoint.port());
903 reverse_dataPath.setDstPort(reverse_dstPort);
904
905 SwitchPort reverse_srcPort = new SwitchPort();
906 reverse_srcPort.setDpid(new Dpid(peerInterface.getDpid()));
907 reverse_srcPort.setPort(new Port(peerInterface.getSwitchPort().port()));
908 reverse_dataPath.setSrcPort(reverse_srcPort);
909 flowPath.setDataPath(reverse_dataPath);
910
911 // reverse the dst IP and src IP addresses
912 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
913 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
914 flowPath.setFlowEntryMatch(flowEntryMatch);
915
916 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
917
918 if (flowManagerService.addFlow(flowPath) == null) {
919
920 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
921 bgpPeer.getIpAddress().getHostAddress());
922 }
923 else {
924 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
925 bgpPeer.getIpAddress().getHostAddress());
926 }
927
928 // Reversed BGP flow path for dst-TCP-port
929 //FlowId returnByRefFlowId4 = new FlowId(flowManagerService.getNextFlowEntryId());
930 //flowPath.setFlowId(returnByRefFlowId4);
931 flowPath.setFlowId(new FlowId());
932
933 // Disable src-TCP-port, and set the dst-TCP-port
934 flowEntryMatch.disableSrcTcpUdpPort();
935 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
936 flowPath.setFlowEntryMatch(flowEntryMatch);
937
938 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
939
940 if (flowManagerService.addFlow(flowPath) == null) {
941 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
942 bgpPeer.getIpAddress().getHostAddress());
943 }
944 else {
945 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
946 bgpPeer.getIpAddress().getHostAddress());
947 }
948
949 /**
950 * ICMP paths between BGPd and its peers
951 */
952 //match ICMP protocol BGP <- Peer
953 //FlowId returnByRefFlowId5 = new FlowId(flowManagerService.getNextFlowEntryId());
954 //flowPath.setFlowId(returnByRefFlowId5);
955 flowPath.setFlowId(new FlowId());
956
957 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
958 flowEntryMatch.disableSrcTcpUdpPort();
959 flowEntryMatch.disableDstTcpUdpPort();
960
961 flowPath.setFlowEntryMatch(flowEntryMatch);
962
963 flowPath.setDataPath(reverse_dataPath);
964
965 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
966
967 if (flowManagerService.addFlow(flowPath) == null) {
968
969 log.error("Failed to set up ICMP path BGP <- Peer {}",
970 bgpPeer.getIpAddress().getHostAddress());
971 }
972 else {
973 log.debug("Successfully set up ICMP path BGP <- Peer {}",
974 bgpPeer.getIpAddress().getHostAddress());
975 }
976
977 //match ICMP protocol BGP -> Peer
978 //FlowId returnByRefFlowId6 = new FlowId(flowManagerService.getNextFlowEntryId());
979 //flowPath.setFlowId(returnByRefFlowId6);
980 flowPath.setFlowId(new FlowId());
981
982 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
983 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
984 flowPath.setFlowEntryMatch(flowEntryMatch);
985
986 flowPath.setDataPath(dataPath);
987
988 log.debug("ICMP flowPath: {}", flowPath.toString());
989
990
991 if (flowManagerService.addFlow(flowPath) == null) {
992
993 log.error("Failed to set up ICMP path BGP -> Peer {}",
994 bgpPeer.getIpAddress().getHostAddress());
995 }
996 else {
997 log.debug("Successfully set up ICMP path BGP -> Peer {}",
998 bgpPeer.getIpAddress().getHostAddress());
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200999 }
1000 }
1001 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001002
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001003 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +13001004 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
1005 log.debug("Received ARP response: {} => {}",
1006 ipAddress.getHostAddress(), macAddress);
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001007
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001008 /*
1009 * We synchronize on this to prevent changes to the ptree while we're pushing
1010 * flows to the switches. If the ptree changes, the ptree and switches
1011 * could get out of sync.
1012 */
1013 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001014 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +12001015
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001016 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001017 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001018 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001019 path.getDstInterface().getSwitchPort()});
1020 //These paths should always be to BGP peers. Paths to non-peers are
1021 //handled once the first prefix is ready to push
1022 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001023 //A path already got pushed to this endpoint while we were waiting
1024 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001025 if (path.isPermanent()) {
1026 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +12001027 }
1028 }
1029 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001030 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001031 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +12001032 }
1033 }
1034
Jonathan Hart309889c2013-08-13 23:26:24 +12001035 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
1036
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001037 for (RibUpdate update : prefixesToPush) {
1038 //These will always be adds
1039
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001040 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001041 if (rib != null && rib.equals(update.getRibEntry())) {
1042 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001043 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001044 //We only push prefix flows if the prefix is still in the ptree
1045 //and the next hop is the same as our update. The prefix could
1046 //have been removed while we were waiting for the ARP, or the
1047 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +12001048 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001049 } else {
1050 log.debug("Received ARP response, but {},{} is no longer in ptree",
1051 update.getPrefix(), update.getRibEntry());
1052 }
1053 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001054 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001055 }
1056
pingping-linba5c52f2014-02-11 16:52:01 -08001057 //TODO wait the priority module of the flow Manager
Jonathan Hartc82051c2013-08-24 15:12:20 +12001058 private void setupArpFlows() {
1059 OFMatch match = new OFMatch();
1060 match.setDataLayerType(Ethernet.TYPE_ARP);
1061 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1062
1063 OFFlowMod fm = new OFFlowMod();
1064 fm.setMatch(match);
1065
1066 OFActionOutput action = new OFActionOutput();
1067 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1068 action.setMaxLength((short)0xffff);
1069 List<OFAction> actions = new ArrayList<OFAction>(1);
1070 actions.add(action);
1071 fm.setActions(actions);
1072
1073 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001074 .setHardTimeout((short)0)
1075 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1076 .setCookie(0)
1077 .setCommand(OFFlowMod.OFPFC_ADD)
1078 .setPriority(ARP_PRIORITY)
Jonathan Hartc82051c2013-08-24 15:12:20 +12001079 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1080
1081 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001082 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +12001083 }
1084 }
pingping-linba5c52f2014-02-11 16:52:01 -08001085 //TODO need update, waiting for the priority feature from flow Manager
Jonathan Hartf886fa12013-09-18 14:46:29 +12001086 private void setupDefaultDropFlows() {
1087 OFFlowMod fm = new OFFlowMod();
1088 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001089 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Jonathan Hartf886fa12013-09-18 14:46:29 +12001090
1091 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001092 .setHardTimeout((short)0)
1093 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1094 .setCookie(0)
1095 .setCommand(OFFlowMod.OFPFC_ADD)
1096 .setPriority((short)0)
Jonathan Hartf886fa12013-09-18 14:46:29 +12001097 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
1098
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001099 OFFlowMod fmLLDP;
1100 OFFlowMod fmBDDP;
1101 try {
pingping-linba5c52f2014-02-11 16:52:01 -08001102 fmLLDP = fm.clone();
1103 fmBDDP = fm.clone();
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001104 } catch (CloneNotSupportedException e1) {
1105 log.error("Error cloning flow mod", e1);
1106 return;
1107 }
1108
1109 OFMatch matchLLDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001110 matchLLDP.setDataLayerType((short)0x88cc);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001111 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1112 fmLLDP.setMatch(matchLLDP);
1113
1114 OFMatch matchBDDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001115 matchBDDP.setDataLayerType((short)0x8942);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001116 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1117 fmBDDP.setMatch(matchBDDP);
1118
1119 OFActionOutput action = new OFActionOutput();
1120 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1121 action.setMaxLength((short)0xffff);
1122 List<OFAction> actions = new ArrayList<OFAction>(1);
1123 actions.add(action);
1124
1125 fmLLDP.setActions(actions);
1126 fmBDDP.setActions(actions);
1127
1128 fmLLDP.setPriority(ARP_PRIORITY);
1129 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1130 fmBDDP.setPriority(ARP_PRIORITY);
1131 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1132
Jonathan Hart1912afc2013-10-11 12:02:44 +13001133 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1134 flowModList.add(fm);
1135 flowModList.add(fmLLDP);
1136 flowModList.add(fmBDDP);
1137
Jonathan Hartf886fa12013-09-18 14:46:29 +12001138 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001139 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001140 }
1141 }
1142
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001143 private void beginRouting(){
1144 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001145 topology = topologyNetService.newDatabaseTopology();
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001146
pingping-linba5c52f2014-02-11 16:52:01 -08001147 // Wait Pavlin's API. We need the following functions.
1148 /*setupArpFlows();
1149 setupDefaultDropFlows();*/
Jonathan Hartc82051c2013-08-24 15:12:20 +12001150
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001151 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001152 setupFullMesh();
Jonathan Harte7694532013-09-12 12:34:46 +12001153
1154 //Suppress link discovery on external-facing router ports
1155 for (Interface intf : interfaces.values()) {
1156 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1157 }
1158
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001159 bgpUpdatesExecutor.execute(new Runnable() {
1160 @Override
1161 public void run() {
1162 doUpdatesThread();
1163 }
1164 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001165 }
1166
pingping-linba5c52f2014-02-11 16:52:01 -08001167 // Before inserting the paths for BGP traffic, we should check
1168 // whether all the switches in the configure file are discovered by onos.
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001169 private void checkSwitchesConnected(){
1170 for (String dpid : switches){
pingping-linba5c52f2014-02-11 16:52:01 -08001171 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1172 getActiveSwitches().iterator();
1173 while(activeSwitches.hasNext())
1174 {
1175 ISwitchObject switchObject = activeSwitches.next();
1176 if (switchObject.getDPID().equals(dpid)) {
1177 break;
1178 }
1179 if(activeSwitches.hasNext() == false) {
1180 log.debug("Not all switches are here yet");
1181 return;
1182 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001183 }
1184 }
1185 switchesConnected = true;
1186 }
1187
Jonathan Hartc824ad02013-07-03 15:58:45 +12001188 //Actually we only need to go half way round to verify full mesh connectivity
1189 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001190 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001191 for (Interface dstInterface : interfaces.values()) {
1192 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -07001193 if (dstInterface.equals(srcInterface)) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001194 continue;
1195 }
1196
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001197 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001198 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001199
1200 if (shortestPath == null){
1201 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001202 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001203 return;
1204 }
1205 }
1206 }
1207 topologyReady = true;
1208 }
1209
1210 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001211 if (!switchesConnected){
1212 checkSwitchesConnected();
1213 }
1214 boolean oldTopologyReadyStatus = topologyReady;
1215 if (switchesConnected && !topologyReady){
1216 checkTopologyReady();
1217 }
1218 if (!oldTopologyReadyStatus && topologyReady){
1219 beginRouting();
1220 }
1221 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001222
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001223 private void doUpdatesThread() {
1224 boolean interrupted = false;
1225 try {
1226 while (true) {
1227 try {
1228 RibUpdate update = ribUpdates.take();
1229 switch (update.getOperation()){
1230 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001231 if (validateUpdate(update)) {
1232 processRibAdd(update);
1233 }
1234 else {
1235 log.debug("Rib UPDATE out of order: {} via {}",
1236 update.getPrefix(), update.getRibEntry().getNextHop());
1237 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001238 break;
1239 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001240 if (validateUpdate(update)) {
1241 processRibDelete(update);
1242 }
1243 else {
1244 log.debug("Rib DELETE out of order: {} via {}",
1245 update.getPrefix(), update.getRibEntry().getNextHop());
1246 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001247 break;
1248 }
1249 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001250 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001251 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001252 } catch (Exception e) {
1253 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001254 }
1255 }
1256 } finally {
1257 if (interrupted) {
1258 Thread.currentThread().interrupt();
1259 }
1260 }
1261 }
Jonathan Harte4c98692013-10-18 17:40:03 -07001262
1263 private boolean validateUpdate(RibUpdate update) {
1264 RibEntry newEntry = update.getRibEntry();
1265 RibEntry oldEntry = ptree.lookup(update.getPrefix());
1266
1267 //If there is no existing entry we must assume this is the most recent
1268 //update. However this might not always be the case as we might have a
1269 //POST then DELETE reordering.
1270 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1271 if (oldEntry == null) {
1272 return true;
1273 }
1274
1275 // This handles the case where routes are gathered in the initial
1276 // request because they don't have sequence number info
1277 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1278 return true;
1279 }
1280
1281 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1282 return true;
1283 }
1284 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1285 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1286 return true;
1287 }
1288 else {
1289 return false;
1290 }
1291 }
1292 else {
1293 return false;
1294 }
1295 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001296
1297 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001298 public void topologyChanged() {
1299 if (topologyReady) {
1300 return;
1301 }
1302
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001303 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001304 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001305 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1306 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001307 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001308 refreshNeeded = true;
1309 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001310
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001311 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001312
Jonathan Hart98957bf2013-07-01 14:49:24 +12001313 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1314 synchronized (linkUpdates) {
1315 linkUpdates.add(ldu);
1316 }
1317 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001318 }
1319
Jonathan Hart64c0b202013-08-20 15:45:07 +12001320 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001321 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001322 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001323 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001324
1325 @Override
1326 public void addedSwitch(IOFSwitch sw) {
1327 if (!topologyReady) {
1328 sw.clearAllFlowMods();
1329 }
Jonathan Hart1912afc2013-10-11 12:02:44 +13001330
1331 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001332 }
1333
1334 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001335 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001336
1337 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001338 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001339
1340 @Override
1341 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001342 return "BgpRoute";
1343 }
1344
1345 /*
Jonathan Harta8887642013-10-28 13:46:54 -07001346 * IConfigInfoService methods
Jonathan Hart08ee8522013-09-22 17:34:43 +12001347 */
1348
1349 @Override
1350 public boolean isInterfaceAddress(InetAddress address) {
1351 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1352 return (intf != null && intf.getIpAddress().equals(address));
1353 }
1354
1355 @Override
1356 public boolean inConnectedNetwork(InetAddress address) {
1357 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1358 return (intf != null && !intf.getIpAddress().equals(address));
1359 }
1360
1361 @Override
1362 public boolean fromExternalNetwork(long inDpid, short inPort) {
1363 for (Interface intf : interfaces.values()) {
1364 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1365 return true;
1366 }
1367 }
1368 return false;
1369 }
1370
1371 @Override
1372 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1373 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1374 }
1375
1376 @Override
1377 public boolean hasLayer3Configuration() {
1378 return !interfaces.isEmpty();
1379 }
1380
1381 @Override
1382 public MACAddress getRouterMacAddress() {
1383 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001384 }
Jonathan Harta8887642013-10-28 13:46:54 -07001385
1386 @Override
1387 public short getVlan() {
1388 return vlan;
1389 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001390}