blob: a3cb17b219df01d472cfe6115920be0470ab3c7c [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;
pingping-linba5c52f2014-02-11 16:52:01 -080036import net.onrc.onos.ofcontroller.core.IDeviceStorage;
37import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
38import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
Jonathan Hart98957bf2013-07-01 14:49:24 +120039import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
pingping-linba5c52f2014-02-11 16:52:01 -080040import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoSwitchService;
Jonathan Hartebba1e12013-10-29 11:37:02 -070041import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
pingping-linba5c52f2014-02-11 16:52:01 -080042import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
Jonathan Hart98957bf2013-07-01 14:49:24 +120043import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
pingping-linba5c52f2014-02-11 16:52:01 -080044import net.onrc.onos.ofcontroller.core.internal.TopoSwitchServiceImpl;
45import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070046import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
47import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harte7694532013-09-12 12:34:46 +120048import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120049import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
pingping-linba5c52f2014-02-11 16:52:01 -080050import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070051import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070052import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070053import net.onrc.onos.ofcontroller.topology.TopologyManager;
pingping-linba5c52f2014-02-11 16:52:01 -080054import net.onrc.onos.ofcontroller.util.CallerId;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070055import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120056import net.onrc.onos.ofcontroller.util.Dpid;
pingping-linba5c52f2014-02-11 16:52:01 -080057import net.onrc.onos.ofcontroller.util.FlowEntryAction;
58import net.onrc.onos.ofcontroller.util.FlowEntryActions;
59import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
60import net.onrc.onos.ofcontroller.util.FlowId;
61import net.onrc.onos.ofcontroller.util.FlowPath;
62import net.onrc.onos.ofcontroller.util.FlowPathFlags;
63import net.onrc.onos.ofcontroller.util.FlowPathType;
64import net.onrc.onos.ofcontroller.util.FlowPathUserState;
65import net.onrc.onos.ofcontroller.util.IPv4Net;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070066import net.onrc.onos.ofcontroller.util.Port;
67import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080068import net.sf.json.JSONArray;
69import net.sf.json.JSONObject;
70import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080071
Jonathan Hartd1f23252013-06-13 15:17:05 +120072import org.codehaus.jackson.JsonParseException;
73import org.codehaus.jackson.map.JsonMappingException;
74import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070075import org.openflow.protocol.OFFlowMod;
76import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070077import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120078import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070079import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070080import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120081import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080082import org.slf4j.Logger;
83import org.slf4j.LoggerFactory;
84
Jonathan Hart4dfc3652013-08-02 20:22:36 +120085import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120086import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120087import com.google.common.collect.Multimaps;
88import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120089import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120090import com.google.common.util.concurrent.ThreadFactoryBuilder;
91
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070092public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120093 ITopologyListener, IArpRequester,
Jonathan Hart7804bea2014-01-07 10:50:52 -080094 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070095
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070096 private final static Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080097
Jonathan Hartf247ee72013-10-18 18:57:28 -070098 private IFloodlightProviderService floodlightProvider;
Jonathan Hart3a326122013-10-21 11:51:13 -070099 private ITopologyService topologyService;
Jonathan Hartf247ee72013-10-18 18:57:28 -0700100 private ITopologyNetService topologyNetService;
101 private ILinkDiscoveryService linkDiscoveryService;
102 private IRestApiService restApi;
pingping-linba5c52f2014-02-11 16:52:01 -0800103 private IProxyArpService proxyArp;
104 protected volatile IFlowService flowManagerService;
105 private IDeviceStorage deviceStorage;
106 private ITopoSwitchService topoSwitchService;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700107
Jonathan Hartf247ee72013-10-18 18:57:28 -0700108 private IPatriciaTrie<RibEntry> ptree;
109 private IPatriciaTrie<Interface> interfacePtrie;
110 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700111
Jonathan Hartf247ee72013-10-18 18:57:28 -0700112 private String bgpdRestIp;
113 private String routerId;
114 private String configFilename = "config.json";
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700115
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700116 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
117 //the controller/OS should hand out cookie IDs to prevent conflicts.
Jonathan Hartf247ee72013-10-18 18:57:28 -0700118 private final long APP_COOKIE = 0xa0000000000000L;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700119 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Jonathan Hartf247ee72013-10-18 18:57:28 -0700120 private final long L2_FWD_COOKIE = APP_COOKIE + 1;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700121 //Cookie for flows in ingress switches that rewrite the MAC address
Jonathan Hartf247ee72013-10-18 18:57:28 -0700122 private final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200123 //Cookie for flows that setup BGP paths
Jonathan Hartf247ee72013-10-18 18:57:28 -0700124 private final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200125 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
126 //need to be higher priority than this otherwise the rewrite may not get done
Jonathan Hartf247ee72013-10-18 18:57:28 -0700127 private final short SDNIP_PRIORITY = 10;
128 private final short ARP_PRIORITY = 20;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700129
Jonathan Hartf247ee72013-10-18 18:57:28 -0700130 private final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700131
Jonathan Hartf247ee72013-10-18 18:57:28 -0700132 private final int TOPO_DETECTION_WAIT = 2; //seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700133
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200134 //Configuration stuff
Jonathan Hartf247ee72013-10-18 18:57:28 -0700135 private List<String> switches;
136 private Map<String, Interface> interfaces;
137 private Map<InetAddress, BgpPeer> bgpPeers;
138 private SwitchPort bgpdAttachmentPoint;
139 private MACAddress bgpdMacAddress;
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700140 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700141
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200142 //True when all switches have connected
Jonathan Hartf247ee72013-10-18 18:57:28 -0700143 private volatile boolean switchesConnected = false;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200144 //True when we have a full mesh of shortest paths between gateways
Jonathan Hartf247ee72013-10-18 18:57:28 -0700145 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200146
Jonathan Hartf247ee72013-10-18 18:57:28 -0700147 private ArrayList<LDUpdate> linkUpdates;
148 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700149
Jonathan Hartf247ee72013-10-18 18:57:28 -0700150 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700151
Jonathan Hartf247ee72013-10-18 18:57:28 -0700152 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700153
Jonathan Hartf247ee72013-10-18 18:57:28 -0700154 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700155
Jonathan Hartf247ee72013-10-18 18:57:28 -0700156 private Map<InetAddress, Path> pushedPaths;
157 private Map<Prefix, Path> prefixToPath;
pingping-linba5c52f2014-02-11 16:52:01 -0800158// private Multimap<Prefix, PushedFlowMod> pushedFlows;
159 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700160
Jonathan Hart1912afc2013-10-11 12:02:44 +1300161 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700162
Jonathan Hart3a326122013-10-21 11:51:13 -0700163 private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700164
Jonathan Hartf247ee72013-10-18 18:57:28 -0700165 private class TopologyChangeDetector implements Runnable {
Jonathan Hart98957bf2013-07-01 14:49:24 +1200166 @Override
167 public void run() {
168 log.debug("Running topology change detection task");
169 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200170 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200171 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700172
Jonathan Hart98957bf2013-07-01 14:49:24 +1200173 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700174
Jonathan Hart98957bf2013-07-01 14:49:24 +1200175 Iterator<LDUpdate> it = linkUpdates.iterator();
176 while (it.hasNext()){
177 LDUpdate ldu = it.next();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700178 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
Jonathan Hart98957bf2013-07-01 14:49:24 +1200179 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700180
Jonathan Hart98957bf2013-07-01 14:49:24 +1200181 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200182 it.remove();
183 }
184 }
185 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700186
Jonathan Hart64c0b202013-08-20 15:45:07 +1200187 if (!topologyReady) {
188 if (linkUpdates.isEmpty()){
189 //All updates have been seen in network map.
190 //We can check if topology is ready
191 log.debug("No known changes outstanding. Checking topology now");
192 checkStatus();
193 }
194 else {
195 //We know of some link updates that haven't propagated to the database yet
196 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
197 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
198 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200199 }
200 }
201 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700202
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700203 private void readConfiguration(String configFilename){
204 File gatewaysFile = new File(configFilename);
Jonathan Hartd1f23252013-06-13 15:17:05 +1200205 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700206
Jonathan Hartd1f23252013-06-13 15:17:05 +1200207 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200208 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700209
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200210 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200211 interfaces = new HashMap<String, Interface>();
212 for (Interface intf : config.getInterfaces()){
213 interfaces.put(intf.getName(), intf);
214 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200215 bgpPeers = new HashMap<InetAddress, BgpPeer>();
216 for (BgpPeer peer : config.getPeers()){
217 bgpPeers.put(peer.getIpAddress(), peer);
218 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700219
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200220 bgpdAttachmentPoint = new SwitchPort(
221 new Dpid(config.getBgpdAttachmentDpid()),
222 new Port(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700223
Jonathan Hart2f790d22013-08-15 14:01:24 +1200224 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700225 vlan = config.getVlan();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200226 } catch (JsonParseException e) {
227 log.error("Error in JSON file", e);
228 System.exit(1);
229 } catch (JsonMappingException e) {
230 log.error("Error in JSON file", e);
231 System.exit(1);
232 } catch (IOException e) {
233 log.error("Error reading JSON file", e);
234 System.exit(1);
235 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700236
Jonathan Hartabf10222013-08-13 10:19:34 +1200237 //Populate the interface Patricia Trie
238 for (Interface intf : interfaces.values()) {
239 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
240 interfacePtrie.put(prefix, intf);
241 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700242 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700243
pingping-lina2cbfad2013-03-07 08:39:21 +0800244 @Override
245 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700246 Collection<Class<? extends IFloodlightService>> l
Jonathan Hart61ba9372013-05-19 20:10:29 -0700247 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800248 l.add(IBgpRouteService.class);
Jonathan Harta8887642013-10-28 13:46:54 -0700249 l.add(IConfigInfoService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800250 return l;
251 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700252
pingping-lina2cbfad2013-03-07 08:39:21 +0800253 @Override
254 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700255 Map<Class<? extends IFloodlightService>, IFloodlightService> m
Jonathan Hart61ba9372013-05-19 20:10:29 -0700256 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800257 m.put(IBgpRouteService.class, this);
Jonathan Harta8887642013-10-28 13:46:54 -0700258 m.put(IConfigInfoService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800259 return m;
260 }
261
pingping-lina2cbfad2013-03-07 08:39:21 +0800262 @Override
263 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700264 Collection<Class<? extends IFloodlightService>> l
Jonathan Hart61ba9372013-05-19 20:10:29 -0700265 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800266 l.add(IFloodlightProviderService.class);
267 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700268 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800269 return l;
270 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700271
pingping-lina2cbfad2013-03-07 08:39:21 +0800272 @Override
273 public void init(FloodlightModuleContext context)
274 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700275
Jonathan Hart29b972d2013-08-12 23:43:51 +1200276 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200277 interfacePtrie = new PatriciaTrie<Interface>(32);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700278
pingping-linba5c52f2014-02-11 16:52:01 -0800279 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700280
pingping-lina2cbfad2013-03-07 08:39:21 +0800281 // Register floodlight provider and REST handler.
282 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700283 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200284 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200285 restApi = context.getServiceImpl(IRestApiService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800286 flowManagerService = context.getServiceImpl(IFlowService.class);
287 proxyArp = context.getServiceImpl(IProxyArpService.class);
288
289 deviceStorage = new DeviceStorageImpl();
290 deviceStorage.init("", "");
291
Jonathan Hart98957bf2013-07-01 14:49:24 +1200292 linkUpdates = new ArrayList<LDUpdate>();
293 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
294 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700295
yoshif7424e42013-11-25 22:07:40 -0800296 topologyNetService = new TopologyManager(context);
pingping-linba5c52f2014-02-11 16:52:01 -0800297 topoSwitchService = new TopoSwitchServiceImpl();
298
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200299 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200300 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
301 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700302
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200303 pushedPaths = new HashMap<InetAddress, Path>();
304 prefixToPath = new HashMap<Prefix, Path>();
pingping-linba5c52f2014-02-11 16:52:01 -0800305// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
306 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700307
Jonathan Hart1912afc2013-10-11 12:02:44 +1300308 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700309
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200310 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
311 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700312
Jonathan Hart61ba9372013-05-19 20:10:29 -0700313 //Read in config values
314 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
315 if (bgpdRestIp == null){
316 log.error("BgpdRestIp property not found in config file");
317 System.exit(1);
318 }
319 else {
320 log.info("BgpdRestIp set to {}", bgpdRestIp);
321 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700322
Jonathan Hart61ba9372013-05-19 20:10:29 -0700323 routerId = context.getConfigParams(this).get("RouterId");
324 if (routerId == null){
325 log.error("RouterId property not found in config file");
326 System.exit(1);
327 }
328 else {
329 log.info("RouterId set to {}", routerId);
330 }
pingping-linba5c52f2014-02-11 16:52:01 -0800331
Jonathan Hart9575cb62013-07-05 13:43:49 +1200332 String configFilenameParameter = context.getConfigParams(this).get("configfile");
333 if (configFilenameParameter != null){
334 configFilename = configFilenameParameter;
335 }
336 log.debug("Config file set to {}", configFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700337
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700338 readConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200339 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700340
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200341 @Override
342 public void startUp(FloodlightModuleContext context) {
343 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700344 topologyService.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200345 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800346
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200347 //Retrieve the RIB from BGPd during startup
348 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800349 }
350
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700351 @Override
Jonathan Hart29b972d2013-08-12 23:43:51 +1200352 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800353 return ptree;
354 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700355
356 @Override
Jonathan Hart61ba9372013-05-19 20:10:29 -0700357 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200358 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800359 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700360
361 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800362 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700363 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800364 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700365
366 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800367 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700368 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800369 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700370
Jonathan Hart61ba9372013-05-19 20:10:29 -0700371 private void retrieveRib(){
372 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
373 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700374
Jonathan Hart61ba9372013-05-19 20:10:29 -0700375 if (response.equals("")){
376 return;
377 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700378
Jonathan Hart61ba9372013-05-19 20:10:29 -0700379 response = response.replaceAll("\"", "'");
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700380 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700381 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
382 String router_id = jsonObj.getString("router-id");
383
384 int size = rib_json_array.size();
385
386 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700387
Jonathan Hart61ba9372013-05-19 20:10:29 -0700388 for (int j = 0; j < size; j++) {
389 JSONObject second_json_object = rib_json_array.getJSONObject(j);
390 String prefix = second_json_object.getString("prefix");
391 String nexthop = second_json_object.getString("nexthop");
392
393 //insert each rib entry into the local rib;
394 String[] substring = prefix.split("/");
395 String prefix1 = substring[0];
396 String mask1 = substring[1];
397
398 Prefix p;
399 try {
400 p = new Prefix(prefix1, Integer.valueOf(mask1));
401 } catch (NumberFormatException e) {
402 log.warn("Wrong mask format in RIB JSON: {}", mask1);
403 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200404 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700405 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
406 continue;
407 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700408
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200409 RibEntry rib = new RibEntry(router_id, nexthop);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700410
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200411 try {
412 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
413 } catch (InterruptedException e) {
414 log.debug("Interrupted while pushing onto update queue");
415 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700416 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700417 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700418
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200419 @Override
420 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200421 try {
422 ribUpdates.put(update);
423 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200424 log.debug("Interrupted while putting on ribUpdates queue", e);
425 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200426 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200427 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700428
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200429 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200430 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700431
Jonathan Hart9ea31212013-08-12 21:40:34 +1200432 log.debug("Processing prefix add {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700433
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200434 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700435
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200436 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200437 //There was an existing nexthop for this prefix. This update supersedes that,
438 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200439 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200440 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700441
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200442 if (update.getRibEntry().getNextHop().equals(
443 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200444 //Route originated by SDN domain
445 //We don't handle these at the moment
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700446 log.debug("Own route {} to {}", prefix,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200447 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200448 return;
449 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700450
Jonathan Hart309889c2013-08-13 23:26:24 +1200451 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200452 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700453
Jonathan Hart309889c2013-08-13 23:26:24 +1200454 private void _processRibAdd(RibUpdate update) {
455 Prefix prefix = update.getPrefix();
456 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700457
Jonathan Hart309889c2013-08-13 23:26:24 +1200458 InetAddress dstIpAddress = rib.getNextHop();
pingping-linba5c52f2014-02-11 16:52:01 -0800459 MACAddress nextHopMacAddress;
460
461 // See if we know the MAC address of the next hop
462 // TODO if we do not treat the next hop as a device in the future, we need to update this
463 IDeviceObject nextHopDevice =
464 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700465
pingping-linba5c52f2014-02-11 16:52:01 -0800466 if (nextHopDevice == null){
467 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
468 prefixesWaitingOnArp.put(dstIpAddress,
469 new RibUpdate(Operation.UPDATE, prefix, rib));
470 proxyArp.sendArpRequest(dstIpAddress, this, true);
471 return;
472
473 }
474 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700475
pingping-linba5c52f2014-02-11 16:52:01 -0800476 // Find the attachment point (egress interface) of the next hop
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200477 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200478 if (bgpPeers.containsKey(dstIpAddress)) {
479 //Route to a peer
480 log.debug("Route to peer {}", dstIpAddress);
481 BgpPeer peer = bgpPeers.get(dstIpAddress);
482 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200483 }
484 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200485 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200486 log.debug("Route to non-peer {}", dstIpAddress);
487 egressInterface = interfacePtrie.match(
488 new Prefix(dstIpAddress.getAddress(), 32));
489 if (egressInterface == null) {
490 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
491 return;
492 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200493 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700494
Jonathan Hart309889c2013-08-13 23:26:24 +1200495 if (nextHopMacAddress == null) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700496 prefixesWaitingOnArp.put(dstIpAddress,
Jonathan Hart309889c2013-08-13 23:26:24 +1200497 new RibUpdate(Operation.UPDATE, prefix, rib));
498 proxyArp.sendArpRequest(dstIpAddress, this, true);
499 return;
500 }
501 else {
502 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200503 //If the prefix is for a non-peer we need to ensure there's a path,
504 //and push one if there isn't.
505 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200506 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200507 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300508 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200509 pushedPaths.put(dstIpAddress, path);
510 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700511
Jonathan Hart309889c2013-08-13 23:26:24 +1200512 path.incrementUsers();
513 prefixToPath.put(prefix, path);
514 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700515
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200516 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200517 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
518 }
519 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700520
pingping-linba5c52f2014-02-11 16:52:01 -0800521 /**
522 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
523 * to all other border switches
524 */
525 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
526 MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700527 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300528 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700529
pingping-linba5c52f2014-02-11 16:52:01 -0800530 FlowPath flowPath = new FlowPath();
531 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700532
pingping-linba5c52f2014-02-11 16:52:01 -0800533 // Set flowPath FlowPathType and FlowPathUserState
534 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
535 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
536
537 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
538 // only to the first-host switches
539 FlowPathFlags flowPathFlags = new FlowPathFlags();
540 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
541 flowPath.setFlowPathFlags(flowPathFlags);
542
543 // Create the DataPath object: dstSwitchPort
544 SwitchPort dstPort = new SwitchPort();
545 dstPort.setDpid(new Dpid(egressInterface.getDpid()));
546 dstPort.setPort(new Port(egressInterface.getPort()));
547
548 // We only need one flow mod per switch, so pick one interface on each switch
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200549 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
550 for (Interface intf : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700551 if (!srcInterfaces.containsKey(intf.getDpid())
Jonathan Hart45107222013-10-22 17:35:04 -0700552 && !intf.equals(egressInterface)) {
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200553 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200554 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200555 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200556 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800557
558 if (egressInterface.equals(srcInterface)){
559 continue;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200560 }
pingping-linba5c52f2014-02-11 16:52:01 -0800561
562 // Create flowPath FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800563 flowPath.setFlowId(new FlowId());
564
565 // Create DataPath object: srcSwitchPort
566 SwitchPort srcPort = new SwitchPort();
567 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
568 srcPort.setPort(new Port(srcInterface.getPort()));
569
570 DataPath dataPath = new DataPath();
571 dataPath.setSrcPort(srcPort);
572 dataPath.setDstPort(dstPort);
573 flowPath.setDataPath(dataPath);
574
575 // Create flow path matching condition(s): IPv4 Prefix
576 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
577 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
578 IPv4Net dstIPv4Net= new IPv4Net(prefix.toString());
579 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
580 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300581
582 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800583 * Create the Flow Entry Action(s): dst-MAC rewrite action
Jonathan Hart1912afc2013-10-11 12:02:44 +1300584 */
pingping-linba5c52f2014-02-11 16:52:01 -0800585 FlowEntryActions flowEntryActions = new FlowEntryActions();
586 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
587 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
588 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
589 flowEntryActions.addAction(flowEntryAction1);
590 flowPath.setFlowEntryActions(flowEntryActions);
591
592 // Flow Path installation, only to first hop switches
593 if (flowManagerService.addFlow(flowPath) == null) {
594 log.error("Failed to install flow path to the first hop for " +
595 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
596 nextHopMacAddress);
597 }
598 else {
599 log.debug("Successfully installed flow path to the first hop " +
600 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
601 nextHopMacAddress);
602
603 pushedFlowIds.put(prefix, flowPath.flowId());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200604 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200605 }
606 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700607
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200608 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200609 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700610
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200611 if (ptree.remove(prefix, update.getRibEntry())) {
612 /*
613 * Only delete flows if an entry was actually removed from the trie.
614 * If no entry was removed, the <prefix, nexthop> wasn't there so
615 * it's probably already been removed and we don't need to do anything
616 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200617 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200618 }
619 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700620
Jonathan Hart309889c2013-08-13 23:26:24 +1200621 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
622 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700623
Jonathan Hart309889c2013-08-13 23:26:24 +1200624 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700625
Jonathan Hart309889c2013-08-13 23:26:24 +1200626 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
627 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200628 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700629
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200630 if (path != null) {
631 //path could be null if we added to the Ptree but didn't push
632 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700633
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200634 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200635 if (path.getUsers() <= 0 && !path.isPermanent()) {
636 deletePath(path);
637 pushedPaths.remove(path.getDstIpAddress());
638 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200639 }
640 }
641 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700642
pingping-linba5c52f2014-02-11 16:52:01 -0800643 // TODO have not tested this module
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200644 private void deletePrefixFlows(Prefix prefix) {
645 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700646
pingping-linba5c52f2014-02-11 16:52:01 -0800647 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
648 for (FlowId flowId : flowIds) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200649 if (log.isTraceEnabled()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800650 //Trace the flow status by flowPath in the switch before deleting it
651 log.trace("Pushing a DELETE flow mod to flowPath : {}",
652 flowManagerService.getFlow(flowId).toString());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200653 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700654
pingping-linba5c52f2014-02-11 16:52:01 -0800655 if( flowManagerService.deleteFlow(flowId))
656 {
657 log.debug("Successfully deleted FlowId: {}",flowId);
658 }
659 else
660 {
661 log.debug("Failed to delete FlowId: {}",flowId);
662 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200663 }
664 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700665
pingping-linba5c52f2014-02-11 16:52:01 -0800666 // TODO need to record the path and then delete here
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200667 private void deletePath(Path path) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700668 log.debug("Deleting flows for path to {}",
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200669 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700670
pingping-linba5c52f2014-02-11 16:52:01 -0800671 // TODO need update
672 /*for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200673 if (log.isTraceEnabled()) {
674 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
675 new Object[] {HexString.toHexString(pfm.getDpid()),
676 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
677 });
678 }
pingping-linba5c52f2014-02-11 16:52:01 -0800679
Jonathan Hart309889c2013-08-13 23:26:24 +1200680 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
pingping-linba5c52f2014-02-11 16:52:01 -0800681 }*/
Jonathan Hart309889c2013-08-13 23:26:24 +1200682 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700683
684
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200685 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200686 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800687
688 /**
689 * On startup, we need to calculate a full mesh of paths between all gateway
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700690 * switches
691 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200692 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700693 //For each border router, calculate and install a path from every other
694 //border switch to said border router. However, don't install the entry
695 //in to the first hop switch, as we need to install an entry to rewrite
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700696 //for each prefix received. This will be done later when prefixes have
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700697 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700698
Jonathan Hartc824ad02013-07-03 15:58:45 +1200699 for (BgpPeer peer : bgpPeers.values()) {
700 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700701
Jonathan Hart309889c2013-08-13 23:26:24 +1200702 //We know there's not already a Path here pushed, because this is
703 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200704 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200705 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700706
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200707 //See if we know the MAC address of the peer. If not we can't
708 //do anything until we learn it
pingping-linba5c52f2014-02-11 16:52:01 -0800709 MACAddress macAddress;
710 IDeviceObject nextHopDevice =
711 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
712
713 if(nextHopDevice == null){
714 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
715 //Put in the pending paths list first
716 pathsWaitingOnArp.put(peer.getIpAddress(), path);
717 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
718 continue;
719 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700720
pingping-linba5c52f2014-02-11 16:52:01 -0800721 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
722
Jonathan Hartabad6a52013-09-30 18:17:21 +1300723 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200724 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
725 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200726 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200727 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
728 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700729 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700730
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200731 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300732 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700733 }
734 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700735
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200736 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200737 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700738
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200739 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
740 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800741
742 FlowPath flowPath = new FlowPath();
743
744 flowPath.setInstallerId(new CallerId("SDNIP"));
745
746 // Set flowPath FlowPathType and FlowPathUserState
747 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
748 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
749
750 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
751 FlowPathFlags flowPathFlags = new FlowPathFlags();
752 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
753 flowPath.setFlowPathFlags(flowPathFlags);
754
755 // Create the DataPath object: dstSwitchPort
756 SwitchPort dstPort = new SwitchPort();
757 dstPort.setDpid(new Dpid(dstInterface.getDpid()));
758 dstPort.setPort(new Port(dstInterface.getPort()));
759
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200760 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800761
Jonathan Hart45107222013-10-22 17:35:04 -0700762 if (dstInterface.equals(srcInterface)){
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200763 continue;
764 }
pingping-linba5c52f2014-02-11 16:52:01 -0800765
766 // Create flowPath FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800767 flowPath.setFlowId(new FlowId());
768
769 // Create the DataPath object: srcSwitchPort
770 SwitchPort srcPort = new SwitchPort();
771 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
772 srcPort.setPort(new Port(srcInterface.getPort()));
773
774 DataPath dataPath = new DataPath();
775 dataPath.setSrcPort(srcPort);
776 dataPath.setDstPort(dstPort);
777 flowPath.setDataPath(dataPath);
778
779 // Create the Flow Path Match condition(s)
780 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
781 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
782 flowEntryMatch.enableDstMac(dstMacAddress);
783 flowPath.setFlowEntryMatch(flowEntryMatch);
784
785 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
786 // Shortest Path Flow, and is always the last action for the Flow Entries
787 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
788 if (flowManagerService.addFlow(flowPath) == null) {
789 log.error("Failed to set up MAC based forwarding path to {}, {}",
790 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200791 }
792 else {
pingping-linba5c52f2014-02-11 16:52:01 -0800793 log.debug("Successfully set up MAC based forwarding path to {}, {}",
794 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200795 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200796 }
797 }
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200798
pingping-linba5c52f2014-02-11 16:52:01 -0800799 /**
800 * Pre-actively install all BGP traffic paths from BGP host attachment point
801 * in SDN network to all the virtual gateways to BGP peers in other networks
802 */
803 private void setupBgpPaths(){
804
805 for (BgpPeer bgpPeer : bgpPeers.values()){
806
807 FlowPath flowPath = new FlowPath();
808 flowPath.setInstallerId(new CallerId("SDNIP"));
809
810 // Set flowPath FlowPathType and FlowPathUserState
811 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
812 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
813
814 // Install flow paths between BGPd and its peers
815 // There is no need to set the FlowPathFlags
816 flowPath.setFlowPathFlags(new FlowPathFlags(0));
817
818 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
819
pingping-linba5c52f2014-02-11 16:52:01 -0800820 // Create the Flow Path Match condition(s)
821 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
822 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
823
824 // Match both source address and dest address
825 IPv4Net dstIPv4Net= new IPv4Net(bgpPeer.getIpAddress().getHostAddress()+"/32");
826 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
827
828 IPv4Net srcIPv4Net= new IPv4Net(peerInterface.getIpAddress().getHostAddress()+"/32");
829 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
830
831 // Match TCP protocol
832 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
833
834 // Match destination TCP port
835 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
836 flowPath.setFlowEntryMatch(flowEntryMatch);
837
838 /**
839 * Create the DataPath: BGP -> BGP peer
840 */
841 // Flow path for src-TCP-port
842 DataPath dataPath = new DataPath();
843
844 SwitchPort srcPort = new SwitchPort();
845 srcPort.setDpid(bgpdAttachmentPoint.dpid());
846 srcPort.setPort(bgpdAttachmentPoint.port());
847 dataPath.setSrcPort(srcPort);
848
849 SwitchPort dstPort = new SwitchPort();
850 dstPort.setDpid(new Dpid(peerInterface.getDpid()));
851 dstPort.setPort(new Port(peerInterface.getSwitchPort().port()));
852 dataPath.setDstPort(dstPort);
853
854 flowPath.setDataPath(dataPath);
855
856 if (flowManagerService.addFlow(flowPath) == null) {
857 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
858 bgpPeer.getIpAddress().getHostAddress());
859 }
860 else {
861 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
862 bgpPeer.getIpAddress().getHostAddress());
863 }
864
865 // Disable dst-TCP-port, and set src-TCP-port
866 flowEntryMatch.disableDstTcpUdpPort();
867 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
868 flowPath.setFlowEntryMatch(flowEntryMatch);
869
870 // Create a new FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800871 flowPath.setFlowId(new FlowId());
872
873 if (flowManagerService.addFlow(flowPath) == null) {
874 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
875 bgpPeer.getIpAddress().getHostAddress());
876 }
877 else {
878 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
879 bgpPeer.getIpAddress().getHostAddress());
880 }
881
882 /**
883 * Create the DataPath: BGP <-BGP peer
884 */
885 // Reversed BGP flow path for src-TCP-port
pingping-linba5c52f2014-02-11 16:52:01 -0800886 flowPath.setFlowId(new FlowId());
887
888 DataPath reverse_dataPath = new DataPath();
889
890 SwitchPort reverse_dstPort = new SwitchPort();
891 reverse_dstPort.setDpid(bgpdAttachmentPoint.dpid());
892 reverse_dstPort.setPort(bgpdAttachmentPoint.port());
893 reverse_dataPath.setDstPort(reverse_dstPort);
894
895 SwitchPort reverse_srcPort = new SwitchPort();
896 reverse_srcPort.setDpid(new Dpid(peerInterface.getDpid()));
897 reverse_srcPort.setPort(new Port(peerInterface.getSwitchPort().port()));
898 reverse_dataPath.setSrcPort(reverse_srcPort);
899 flowPath.setDataPath(reverse_dataPath);
900
901 // reverse the dst IP and src IP addresses
902 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
903 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
904 flowPath.setFlowEntryMatch(flowEntryMatch);
905
906 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
907
908 if (flowManagerService.addFlow(flowPath) == null) {
909
910 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
911 bgpPeer.getIpAddress().getHostAddress());
912 }
913 else {
914 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
915 bgpPeer.getIpAddress().getHostAddress());
916 }
917
918 // Reversed BGP flow path for dst-TCP-port
pingping-linba5c52f2014-02-11 16:52:01 -0800919 flowPath.setFlowId(new FlowId());
920
921 // Disable src-TCP-port, and set the dst-TCP-port
922 flowEntryMatch.disableSrcTcpUdpPort();
923 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
924 flowPath.setFlowEntryMatch(flowEntryMatch);
925
926 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700927
pingping-linba5c52f2014-02-11 16:52:01 -0800928 if (flowManagerService.addFlow(flowPath) == null) {
929 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
930 bgpPeer.getIpAddress().getHostAddress());
931 }
932 else {
933 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
934 bgpPeer.getIpAddress().getHostAddress());
935 }
936
937 /**
938 * ICMP paths between BGPd and its peers
939 */
940 //match ICMP protocol BGP <- Peer
pingping-linba5c52f2014-02-11 16:52:01 -0800941 flowPath.setFlowId(new FlowId());
942
943 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
944 flowEntryMatch.disableSrcTcpUdpPort();
945 flowEntryMatch.disableDstTcpUdpPort();
946
947 flowPath.setFlowEntryMatch(flowEntryMatch);
948
949 flowPath.setDataPath(reverse_dataPath);
950
951 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
952
953 if (flowManagerService.addFlow(flowPath) == null) {
954
955 log.error("Failed to set up ICMP path BGP <- Peer {}",
956 bgpPeer.getIpAddress().getHostAddress());
957 }
958 else {
959 log.debug("Successfully set up ICMP path BGP <- Peer {}",
960 bgpPeer.getIpAddress().getHostAddress());
961 }
962
963 //match ICMP protocol BGP -> Peer
pingping-linba5c52f2014-02-11 16:52:01 -0800964 flowPath.setFlowId(new FlowId());
965
966 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
967 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
968 flowPath.setFlowEntryMatch(flowEntryMatch);
969
970 flowPath.setDataPath(dataPath);
971
972 log.debug("ICMP flowPath: {}", flowPath.toString());
973
974
975 if (flowManagerService.addFlow(flowPath) == null) {
976
977 log.error("Failed to set up ICMP path BGP -> Peer {}",
978 bgpPeer.getIpAddress().getHostAddress());
979 }
980 else {
981 log.debug("Successfully set up ICMP path BGP -> Peer {}",
982 bgpPeer.getIpAddress().getHostAddress());
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200983 }
984 }
985 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700986
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200987 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +1300988 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700989 log.debug("Received ARP response: {} => {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300990 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700991
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200992 /*
993 * We synchronize on this to prevent changes to the ptree while we're pushing
994 * flows to the switches. If the ptree changes, the ptree and switches
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700995 * could get out of sync.
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200996 */
997 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200998 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700999
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001000 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001001 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001002 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001003 path.getDstInterface().getSwitchPort()});
1004 //These paths should always be to BGP peers. Paths to non-peers are
1005 //handled once the first prefix is ready to push
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001006 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001007 //A path already got pushed to this endpoint while we were waiting
1008 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001009 if (path.isPermanent()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001010 pushedPaths.get(path.getDstIpAddress()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +12001011 }
1012 }
1013 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001014 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001015 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +12001016 }
1017 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001018
Jonathan Hart309889c2013-08-13 23:26:24 +12001019 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001020
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001021 for (RibUpdate update : prefixesToPush) {
1022 //These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001023
1024 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001025 if (rib != null && rib.equals(update.getRibEntry())) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001026 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001027 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001028 //We only push prefix flows if the prefix is still in the ptree
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001029 //and the next hop is the same as our update. The prefix could
1030 //have been removed while we were waiting for the ARP, or the
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001031 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +12001032 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001033 } else {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001034 log.debug("Received ARP response, but {},{} is no longer in ptree",
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001035 update.getPrefix(), update.getRibEntry());
1036 }
1037 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001038 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001039 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001040
pingping-linba5c52f2014-02-11 16:52:01 -08001041 //TODO wait the priority module of the flow Manager
Jonathan Hartc82051c2013-08-24 15:12:20 +12001042 private void setupArpFlows() {
1043 OFMatch match = new OFMatch();
1044 match.setDataLayerType(Ethernet.TYPE_ARP);
1045 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001046
Jonathan Hartc82051c2013-08-24 15:12:20 +12001047 OFFlowMod fm = new OFFlowMod();
1048 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001049
Jonathan Hartc82051c2013-08-24 15:12:20 +12001050 OFActionOutput action = new OFActionOutput();
1051 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1052 action.setMaxLength((short)0xffff);
1053 List<OFAction> actions = new ArrayList<OFAction>(1);
1054 actions.add(action);
1055 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001056
Jonathan Hartc82051c2013-08-24 15:12:20 +12001057 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001058 .setHardTimeout((short)0)
1059 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1060 .setCookie(0)
1061 .setCommand(OFFlowMod.OFPFC_ADD)
1062 .setPriority(ARP_PRIORITY)
Jonathan Hartc82051c2013-08-24 15:12:20 +12001063 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001064
Jonathan Hartc82051c2013-08-24 15:12:20 +12001065 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001066 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +12001067 }
1068 }
pingping-linba5c52f2014-02-11 16:52:01 -08001069 //TODO need update, waiting for the priority feature from flow Manager
Jonathan Hartf886fa12013-09-18 14:46:29 +12001070 private void setupDefaultDropFlows() {
1071 OFFlowMod fm = new OFFlowMod();
1072 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001073 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001074
Jonathan Hartf886fa12013-09-18 14:46:29 +12001075 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001076 .setHardTimeout((short)0)
1077 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1078 .setCookie(0)
1079 .setCommand(OFFlowMod.OFPFC_ADD)
1080 .setPriority((short)0)
Jonathan Hartf886fa12013-09-18 14:46:29 +12001081 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001082
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001083 OFFlowMod fmLLDP;
1084 OFFlowMod fmBDDP;
1085 try {
pingping-linba5c52f2014-02-11 16:52:01 -08001086 fmLLDP = fm.clone();
1087 fmBDDP = fm.clone();
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001088 } catch (CloneNotSupportedException e1) {
1089 log.error("Error cloning flow mod", e1);
1090 return;
1091 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001092
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001093 OFMatch matchLLDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001094 matchLLDP.setDataLayerType((short)0x88cc);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001095 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1096 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001097
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001098 OFMatch matchBDDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001099 matchBDDP.setDataLayerType((short)0x8942);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001100 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1101 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001102
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001103 OFActionOutput action = new OFActionOutput();
1104 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1105 action.setMaxLength((short)0xffff);
1106 List<OFAction> actions = new ArrayList<OFAction>(1);
1107 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001108
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001109 fmLLDP.setActions(actions);
1110 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001111
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001112 fmLLDP.setPriority(ARP_PRIORITY);
1113 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1114 fmBDDP.setPriority(ARP_PRIORITY);
1115 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001116
1117 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
Jonathan Hart1912afc2013-10-11 12:02:44 +13001118 flowModList.add(fm);
1119 flowModList.add(fmLLDP);
1120 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001121
Jonathan Hartf886fa12013-09-18 14:46:29 +12001122 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001123 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001124 }
1125 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001126
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001127 private void beginRouting(){
1128 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001129 topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001130
pingping-linba5c52f2014-02-11 16:52:01 -08001131 // Wait Pavlin's API. We need the following functions.
1132 /*setupArpFlows();
1133 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001134
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001135 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001136 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001137
Jonathan Harte7694532013-09-12 12:34:46 +12001138 //Suppress link discovery on external-facing router ports
1139 for (Interface intf : interfaces.values()) {
1140 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1141 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001142
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001143 bgpUpdatesExecutor.execute(new Runnable() {
1144 @Override
1145 public void run() {
1146 doUpdatesThread();
1147 }
1148 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001149 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001150
pingping-linba5c52f2014-02-11 16:52:01 -08001151 // Before inserting the paths for BGP traffic, we should check
1152 // whether all the switches in the configure file are discovered by onos.
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001153 private void checkSwitchesConnected(){
1154 for (String dpid : switches){
pingping-linba5c52f2014-02-11 16:52:01 -08001155 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1156 getActiveSwitches().iterator();
1157 while(activeSwitches.hasNext())
1158 {
1159 ISwitchObject switchObject = activeSwitches.next();
1160 if (switchObject.getDPID().equals(dpid)) {
1161 break;
1162 }
1163 if(activeSwitches.hasNext() == false) {
1164 log.debug("Not all switches are here yet");
1165 return;
1166 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001167 }
1168 }
1169 switchesConnected = true;
1170 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001171
Jonathan Hartc824ad02013-07-03 15:58:45 +12001172 //Actually we only need to go half way round to verify full mesh connectivity
1173 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001174 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001175 for (Interface dstInterface : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001176 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -07001177 if (dstInterface.equals(srcInterface)) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001178 continue;
1179 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001180
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001181 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001182 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001183
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001184 if (shortestPath == null){
1185 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001186 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001187 return;
1188 }
1189 }
1190 }
1191 topologyReady = true;
1192 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001193
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001194 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001195 if (!switchesConnected){
1196 checkSwitchesConnected();
1197 }
1198 boolean oldTopologyReadyStatus = topologyReady;
1199 if (switchesConnected && !topologyReady){
1200 checkTopologyReady();
1201 }
1202 if (!oldTopologyReadyStatus && topologyReady){
1203 beginRouting();
1204 }
1205 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001206
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001207 private void doUpdatesThread() {
1208 boolean interrupted = false;
1209 try {
1210 while (true) {
1211 try {
1212 RibUpdate update = ribUpdates.take();
1213 switch (update.getOperation()){
1214 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001215 if (validateUpdate(update)) {
1216 processRibAdd(update);
1217 }
1218 else {
1219 log.debug("Rib UPDATE out of order: {} via {}",
1220 update.getPrefix(), update.getRibEntry().getNextHop());
1221 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001222 break;
1223 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001224 if (validateUpdate(update)) {
1225 processRibDelete(update);
1226 }
1227 else {
1228 log.debug("Rib DELETE out of order: {} via {}",
1229 update.getPrefix(), update.getRibEntry().getNextHop());
1230 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001231 break;
1232 }
1233 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001234 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001235 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001236 } catch (Exception e) {
1237 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001238 }
1239 }
1240 } finally {
1241 if (interrupted) {
1242 Thread.currentThread().interrupt();
1243 }
1244 }
1245 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001246
Jonathan Harte4c98692013-10-18 17:40:03 -07001247 private boolean validateUpdate(RibUpdate update) {
1248 RibEntry newEntry = update.getRibEntry();
1249 RibEntry oldEntry = ptree.lookup(update.getPrefix());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001250
Jonathan Harte4c98692013-10-18 17:40:03 -07001251 //If there is no existing entry we must assume this is the most recent
1252 //update. However this might not always be the case as we might have a
1253 //POST then DELETE reordering.
1254 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1255 if (oldEntry == null) {
1256 return true;
1257 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001258
Jonathan Harte4c98692013-10-18 17:40:03 -07001259 // This handles the case where routes are gathered in the initial
1260 // request because they don't have sequence number info
1261 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1262 return true;
1263 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001264
Jonathan Harte4c98692013-10-18 17:40:03 -07001265 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1266 return true;
1267 }
1268 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1269 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1270 return true;
1271 }
1272 else {
1273 return false;
1274 }
1275 }
1276 else {
1277 return false;
1278 }
1279 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001280
1281 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001282 public void topologyChanged() {
1283 if (topologyReady) {
1284 return;
1285 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001286
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001287 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001288 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001289 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1290 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001291 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001292 refreshNeeded = true;
1293 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001294
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001295 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001296
Jonathan Hart98957bf2013-07-01 14:49:24 +12001297 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1298 synchronized (linkUpdates) {
1299 linkUpdates.add(ldu);
1300 }
1301 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001302 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001303
Jonathan Hart64c0b202013-08-20 15:45:07 +12001304 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001305 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001306 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001307 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001308
1309 @Override
1310 public void addedSwitch(IOFSwitch sw) {
1311 if (!topologyReady) {
1312 sw.clearAllFlowMods();
1313 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001314
Jonathan Hart1912afc2013-10-11 12:02:44 +13001315 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001316 }
1317
1318 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001319 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001320
1321 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001322 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001323
1324 @Override
1325 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001326 return "BgpRoute";
1327 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001328
Jonathan Hart08ee8522013-09-22 17:34:43 +12001329 /*
Jonathan Harta8887642013-10-28 13:46:54 -07001330 * IConfigInfoService methods
Jonathan Hart08ee8522013-09-22 17:34:43 +12001331 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001332
Jonathan Hart08ee8522013-09-22 17:34:43 +12001333 @Override
1334 public boolean isInterfaceAddress(InetAddress address) {
1335 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1336 return (intf != null && intf.getIpAddress().equals(address));
1337 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001338
Jonathan Hart08ee8522013-09-22 17:34:43 +12001339 @Override
1340 public boolean inConnectedNetwork(InetAddress address) {
1341 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1342 return (intf != null && !intf.getIpAddress().equals(address));
1343 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001344
Jonathan Hart08ee8522013-09-22 17:34:43 +12001345 @Override
1346 public boolean fromExternalNetwork(long inDpid, short inPort) {
1347 for (Interface intf : interfaces.values()) {
1348 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1349 return true;
1350 }
1351 }
1352 return false;
1353 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001354
Jonathan Hart08ee8522013-09-22 17:34:43 +12001355 @Override
1356 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1357 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1358 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001359
Jonathan Hart08ee8522013-09-22 17:34:43 +12001360 @Override
1361 public boolean hasLayer3Configuration() {
1362 return !interfaces.isEmpty();
1363 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001364
Jonathan Hart08ee8522013-09-22 17:34:43 +12001365 @Override
1366 public MACAddress getRouterMacAddress() {
1367 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001368 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001369
Jonathan Harta8887642013-10-28 13:46:54 -07001370 @Override
1371 public short getVlan() {
1372 return vlan;
1373 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001374}