blob: eaee714bea8da185cd200cd9c9f92ded3f7430a5 [file] [log] [blame]
Jonathan Hart382623d2014-04-03 09:48:11 -07001package net.onrc.onos.apps.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 Harte7e1c6e2013-06-04 20:50:23 -07009import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070010import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120011import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120012import java.util.concurrent.BlockingQueue;
13import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120014import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120015import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120016import java.util.concurrent.ScheduledExecutorService;
17import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080018
Jonathan Hart61ba9372013-05-19 20:10:29 -070019import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070020import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart64c0b202013-08-20 15:45:07 +120021import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080022import net.floodlightcontroller.core.module.FloodlightModuleContext;
23import net.floodlightcontroller.core.module.FloodlightModuleException;
24import net.floodlightcontroller.core.module.IFloodlightModule;
25import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120026import net.floodlightcontroller.core.util.SingletonTask;
pingping-lina2cbfad2013-03-07 08:39:21 +080027import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120028import net.floodlightcontroller.util.MACAddress;
Jonathan Hart382623d2014-04-03 09:48:11 -070029import net.onrc.onos.apps.bgproute.RibUpdate.Operation;
Jonathan Hart0961fe82014-04-03 09:56:25 -070030import net.onrc.onos.apps.proxyarp.IArpRequester;
31import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart23701d12014-04-03 10:45:48 -070032import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harta99ec672014-04-03 11:30:34 -070033import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070034import net.onrc.onos.core.main.config.IConfigInfoService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070035import net.onrc.onos.core.packet.Ethernet;
36import net.onrc.onos.core.packet.IPv4;
Jonathan Hart23701d12014-04-03 10:45:48 -070037import net.onrc.onos.core.util.CallerId;
38import net.onrc.onos.core.util.DataPath;
39import net.onrc.onos.core.util.Dpid;
40import net.onrc.onos.core.util.FlowEntryAction;
41import net.onrc.onos.core.util.FlowEntryActions;
42import net.onrc.onos.core.util.FlowEntryMatch;
43import net.onrc.onos.core.util.FlowId;
44import net.onrc.onos.core.util.FlowPath;
45import net.onrc.onos.core.util.FlowPathFlags;
46import net.onrc.onos.core.util.FlowPathType;
47import net.onrc.onos.core.util.FlowPathUserState;
48import net.onrc.onos.core.util.IPv4Net;
49import net.onrc.onos.core.util.Port;
50import net.onrc.onos.core.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080051import net.sf.json.JSONArray;
52import net.sf.json.JSONObject;
53import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080054
Jonathan Hartec9ee2e2014-04-08 22:45:44 -070055import org.apache.commons.configuration.ConfigurationRuntimeException;
Jonathan Hartd1f23252013-06-13 15:17:05 +120056import org.codehaus.jackson.JsonParseException;
57import org.codehaus.jackson.map.JsonMappingException;
58import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070059import org.openflow.protocol.OFFlowMod;
60import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070061import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120062import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070063import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070064import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120065import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080066import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
Jonathan Hart4dfc3652013-08-02 20:22:36 +120069import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120070import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120071import com.google.common.collect.Multimaps;
72import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120073import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120074import com.google.common.util.concurrent.ThreadFactoryBuilder;
75
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070076public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Ray Milkey269ffb92014-04-03 14:43:30 -070077 IArpRequester,
78 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070079
Ray Milkeyec838942014-04-09 11:28:43 -070080 private static final Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080081
Ray Milkey269ffb92014-04-03 14:43:30 -070082 private IFloodlightProviderService floodlightProvider;
83 private ILinkDiscoveryService linkDiscoveryService;
84 private IRestApiService restApi;
85 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070086
Ray Milkey269ffb92014-04-03 14:43:30 -070087 private IPatriciaTrie<RibEntry> ptree;
88 private IPatriciaTrie<Interface> interfacePtrie;
89 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070090
Ray Milkey269ffb92014-04-03 14:43:30 -070091 private String bgpdRestIp;
92 private String routerId;
93 private String configFilename = "config.json";
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070094
Ray Milkey2476cac2014-04-08 11:03:21 -070095 private static final short ARP_PRIORITY = 20;
Ray Milkey5d406012014-04-08 14:44:41 -070096
Jonathan Hart938a0152014-04-07 18:27:31 -070097 // The fields below are unused after the move to FlowManager.
98 // Remove them if no longer needed.
99 /*
100 // We need to identify our flows somehow, in lieu of an OS-wide mechanism
101 // to hand out cookie IDs to prevent conflicts.
102 private static final long APP_COOKIE = 0xa0000000000000L;
103 // Cookie for flows that do L2 forwarding within SDN domain to egress routers
104 private static final long L2_FWD_COOKIE = APP_COOKIE + 1;
105 // Cookie for flows in ingress switches that rewrite the MAC address
106 private static final long MAC_RW_COOKIE = APP_COOKIE + 2;
107 // Cookie for flows that setup BGP paths
108 private static final long BGP_COOKIE = APP_COOKIE + 3;
109 // Forwarding uses priority 0, and the mac rewrite entries in ingress switches
110 // need to be higher priority than this otherwise the rewrite may not get done
111 private static final short SDNIP_PRIORITY = 10;
112 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700113
Ray Milkey2476cac2014-04-08 11:03:21 -0700114 private static final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700115
Jonathan Hart938a0152014-04-07 18:27:31 -0700116 private static final int TOPO_DETECTION_WAIT = 2; // seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700117
Jonathan Hart938a0152014-04-07 18:27:31 -0700118 // Configuration stuff
Ray Milkey269ffb92014-04-03 14:43:30 -0700119 private List<String> switches;
120 private Map<String, Interface> interfaces;
121 private Map<InetAddress, BgpPeer> bgpPeers;
122 private SwitchPort bgpdAttachmentPoint;
123 private MACAddress bgpdMacAddress;
124 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700125
Jonathan Hart938a0152014-04-07 18:27:31 -0700126 // True when all switches have connected
Ray Milkey269ffb92014-04-03 14:43:30 -0700127 private volatile boolean switchesConnected = false;
Jonathan Hart938a0152014-04-07 18:27:31 -0700128 // True when we have a full mesh of shortest paths between gateways
Ray Milkey269ffb92014-04-03 14:43:30 -0700129 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200130
Jonathan Hart938a0152014-04-07 18:27:31 -0700131 private List<LDUpdate> linkUpdates;
Ray Milkey269ffb92014-04-03 14:43:30 -0700132 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700133
Ray Milkey269ffb92014-04-03 14:43:30 -0700134 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700135
Ray Milkey269ffb92014-04-03 14:43:30 -0700136 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700137
Ray Milkey269ffb92014-04-03 14:43:30 -0700138 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700139
Ray Milkey269ffb92014-04-03 14:43:30 -0700140 private Map<InetAddress, Path> pushedPaths;
141 private Map<Prefix, Path> prefixToPath;
142 // private Multimap<Prefix, PushedFlowMod> pushedFlows;
143 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700144
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700146
Ray Milkey269ffb92014-04-03 14:43:30 -0700147 // TODO: Fix for the new Topology Network Graph
148 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700149
Ray Milkey269ffb92014-04-03 14:43:30 -0700150 private class TopologyChangeDetector implements Runnable {
151 @Override
152 public void run() {
153 log.debug("Running topology change detection task");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700154 // TODO: Fix the code below after topoLinkService was removed
155 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700156 synchronized (linkUpdates) {
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700157
Ray Milkey269ffb92014-04-03 14:43:30 -0700158 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700159
Ray Milkey269ffb92014-04-03 14:43:30 -0700160 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700161
Ray Milkey269ffb92014-04-03 14:43:30 -0700162 Iterator<LDUpdate> it = linkUpdates.iterator();
163 while (it.hasNext()){
164 LDUpdate ldu = it.next();
165 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
166 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700167
Ray Milkey269ffb92014-04-03 14:43:30 -0700168 if (activeLinks.contains(l)){
169 it.remove();
170 }
171 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700172 }
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700173 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700174
Ray Milkey269ffb92014-04-03 14:43:30 -0700175 if (!topologyReady) {
176 if (linkUpdates.isEmpty()) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700177 // All updates have been seen in network map.
178 // We can check if topology is ready
Ray Milkey269ffb92014-04-03 14:43:30 -0700179 log.debug("No known changes outstanding. Checking topology now");
180 checkStatus();
181 } else {
Jonathan Hart938a0152014-04-07 18:27:31 -0700182 // We know of some link updates that haven't propagated to the database yet
Ray Milkey269ffb92014-04-03 14:43:30 -0700183 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
184 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
185 }
186 }
187 }
188 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700189
Ray Milkey269ffb92014-04-03 14:43:30 -0700190 private void readConfiguration(String configFilename) {
191 File gatewaysFile = new File(configFilename);
192 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700193
Ray Milkey269ffb92014-04-03 14:43:30 -0700194 try {
195 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700196
Ray Milkey269ffb92014-04-03 14:43:30 -0700197 switches = config.getSwitches();
198 interfaces = new HashMap<String, Interface>();
199 for (Interface intf : config.getInterfaces()) {
200 interfaces.put(intf.getName(), intf);
201 }
202 bgpPeers = new HashMap<InetAddress, BgpPeer>();
203 for (BgpPeer peer : config.getPeers()) {
204 bgpPeers.put(peer.getIpAddress(), peer);
205 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700206
Ray Milkey269ffb92014-04-03 14:43:30 -0700207 bgpdAttachmentPoint = new SwitchPort(
208 new Dpid(config.getBgpdAttachmentDpid()),
209 new Port(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700210
Ray Milkey269ffb92014-04-03 14:43:30 -0700211 bgpdMacAddress = config.getBgpdMacAddress();
212 vlan = config.getVlan();
213 } catch (JsonParseException e) {
214 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700215 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700216 } catch (JsonMappingException e) {
217 log.error("Error in JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700218 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700219 } catch (IOException e) {
220 log.error("Error reading JSON file", e);
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700221 throw new ConfigurationRuntimeException("Error in JSON file", e);
Ray Milkey269ffb92014-04-03 14:43:30 -0700222 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700223
Jonathan Hart938a0152014-04-07 18:27:31 -0700224 // Populate the interface Patricia Trie
Ray Milkey269ffb92014-04-03 14:43:30 -0700225 for (Interface intf : interfaces.values()) {
226 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
227 interfacePtrie.put(prefix, intf);
228 }
229 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700230
Ray Milkey269ffb92014-04-03 14:43:30 -0700231 @Override
232 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
233 Collection<Class<? extends IFloodlightService>> l
234 = new ArrayList<Class<? extends IFloodlightService>>();
235 l.add(IBgpRouteService.class);
236 l.add(IConfigInfoService.class);
237 return l;
238 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700239
Ray Milkey269ffb92014-04-03 14:43:30 -0700240 @Override
241 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
242 Map<Class<? extends IFloodlightService>, IFloodlightService> m
243 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
244 m.put(IBgpRouteService.class, this);
245 m.put(IConfigInfoService.class, this);
246 return m;
247 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800248
Ray Milkey269ffb92014-04-03 14:43:30 -0700249 @Override
250 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
251 Collection<Class<? extends IFloodlightService>> l
252 = new ArrayList<Class<? extends IFloodlightService>>();
253 l.add(IFloodlightProviderService.class);
254 l.add(IRestApiService.class);
255 return l;
256 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700257
Ray Milkey269ffb92014-04-03 14:43:30 -0700258 @Override
259 public void init(FloodlightModuleContext context)
260 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700261
Ray Milkey269ffb92014-04-03 14:43:30 -0700262 ptree = new PatriciaTrie<RibEntry>(32);
263 interfacePtrie = new PatriciaTrie<Interface>(32);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700264
Ray Milkey269ffb92014-04-03 14:43:30 -0700265 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700266
Ray Milkey269ffb92014-04-03 14:43:30 -0700267 // Register floodlight provider and REST handler.
268 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
269 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
270 restApi = context.getServiceImpl(IRestApiService.class);
271 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800272
Ray Milkey269ffb92014-04-03 14:43:30 -0700273 linkUpdates = new ArrayList<LDUpdate>();
274 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
275 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700276
Ray Milkey269ffb92014-04-03 14:43:30 -0700277 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
278 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
279 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700280
Ray Milkey269ffb92014-04-03 14:43:30 -0700281 pushedPaths = new HashMap<InetAddress, Path>();
282 prefixToPath = new HashMap<Prefix, Path>();
283// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
284 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700285
Ray Milkey269ffb92014-04-03 14:43:30 -0700286 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700287
Ray Milkey269ffb92014-04-03 14:43:30 -0700288 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
289 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700290
Jonathan Hart938a0152014-04-07 18:27:31 -0700291 // Read in config values
Ray Milkey269ffb92014-04-03 14:43:30 -0700292 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
293 if (bgpdRestIp == null) {
294 log.error("BgpdRestIp property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700295 throw new ConfigurationRuntimeException(
296 "BgpdRestIp property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700297 } else {
298 log.info("BgpdRestIp set to {}", bgpdRestIp);
299 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700300
Ray Milkey269ffb92014-04-03 14:43:30 -0700301 routerId = context.getConfigParams(this).get("RouterId");
302 if (routerId == null) {
303 log.error("RouterId property not found in config file");
Jonathan Hartec9ee2e2014-04-08 22:45:44 -0700304 throw new ConfigurationRuntimeException(
305 "RouterId property not found in config file");
Ray Milkey269ffb92014-04-03 14:43:30 -0700306 } else {
307 log.info("RouterId set to {}", routerId);
308 }
pingping-linba5c52f2014-02-11 16:52:01 -0800309
Ray Milkey269ffb92014-04-03 14:43:30 -0700310 String configFilenameParameter = context.getConfigParams(this).get("configfile");
311 if (configFilenameParameter != null) {
312 configFilename = configFilenameParameter;
313 }
314 log.debug("Config file set to {}", configFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700315
Ray Milkey269ffb92014-04-03 14:43:30 -0700316 readConfiguration(configFilename);
317 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700318
Ray Milkey269ffb92014-04-03 14:43:30 -0700319 @Override
320 public void startUp(FloodlightModuleContext context) {
321 restApi.addRestletRoutable(new BgpRouteWebRoutable());
322 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800323
Jonathan Hart938a0152014-04-07 18:27:31 -0700324 // Retrieve the RIB from BGPd during startup
Ray Milkey269ffb92014-04-03 14:43:30 -0700325 retrieveRib();
326 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800327
Ray Milkey269ffb92014-04-03 14:43:30 -0700328 @Override
329 public IPatriciaTrie<RibEntry> getPtree() {
330 return ptree;
331 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700332
Ray Milkey269ffb92014-04-03 14:43:30 -0700333 @Override
334 public void clearPtree() {
335 ptree = new PatriciaTrie<RibEntry>(32);
336 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700337
Ray Milkey269ffb92014-04-03 14:43:30 -0700338 @Override
339 public String getBGPdRestIp() {
340 return bgpdRestIp;
341 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700342
Ray Milkey269ffb92014-04-03 14:43:30 -0700343 @Override
344 public String getRouterId() {
345 return routerId;
346 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700347
Ray Milkey269ffb92014-04-03 14:43:30 -0700348 private void retrieveRib() {
349 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
350 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700351
Jonathan Hart938a0152014-04-07 18:27:31 -0700352 if ("".equals(response)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700353 return;
354 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700355
Ray Milkey269ffb92014-04-03 14:43:30 -0700356 response = response.replaceAll("\"", "'");
357 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
Jonathan Hart938a0152014-04-07 18:27:31 -0700358 JSONArray ribArray = jsonObj.getJSONArray("rib");
Ray Milkey2476cac2014-04-08 11:03:21 -0700359 String routerId = jsonObj.getString("router-id");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700360
Jonathan Hart938a0152014-04-07 18:27:31 -0700361 int size = ribArray.size();
Jonathan Hart61ba9372013-05-19 20:10:29 -0700362
Ray Milkey269ffb92014-04-03 14:43:30 -0700363 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700364
Ray Milkey269ffb92014-04-03 14:43:30 -0700365 for (int j = 0; j < size; j++) {
Jonathan Hart938a0152014-04-07 18:27:31 -0700366 JSONObject ribEntry = ribArray.getJSONObject(j);
367 String prefix = ribEntry.getString("prefix");
368 String nexthop = ribEntry.getString("nexthop");
Jonathan Hart61ba9372013-05-19 20:10:29 -0700369
Jonathan Hart938a0152014-04-07 18:27:31 -0700370 // Insert each rib entry into the local rib
Ray Milkey269ffb92014-04-03 14:43:30 -0700371 String[] substring = prefix.split("/");
372 String prefix1 = substring[0];
373 String mask1 = substring[1];
Jonathan Hart61ba9372013-05-19 20:10:29 -0700374
Ray Milkey269ffb92014-04-03 14:43:30 -0700375 Prefix p;
376 try {
377 p = new Prefix(prefix1, Integer.valueOf(mask1));
378 } catch (NumberFormatException e) {
379 log.warn("Wrong mask format in RIB JSON: {}", mask1);
380 continue;
381 } catch (IllegalArgumentException e1) {
382 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
383 continue;
384 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700385
Ray Milkey2476cac2014-04-08 11:03:21 -0700386 RibEntry rib = new RibEntry(routerId, nexthop);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700387
Ray Milkey269ffb92014-04-03 14:43:30 -0700388 try {
389 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
390 } catch (InterruptedException e) {
391 log.debug("Interrupted while pushing onto update queue");
392 }
393 }
394 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700395
Ray Milkey269ffb92014-04-03 14:43:30 -0700396 @Override
397 public void newRibUpdate(RibUpdate update) {
398 try {
399 ribUpdates.put(update);
400 } catch (InterruptedException e) {
401 log.debug("Interrupted while putting on ribUpdates queue", e);
402 Thread.currentThread().interrupt();
403 }
404 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700405
Jonathan Hart938a0152014-04-07 18:27:31 -0700406 public void processRibAdd(RibUpdate update) {
407 synchronized (this) {
408 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700409
Jonathan Hart938a0152014-04-07 18:27:31 -0700410 log.debug("Processing prefix add {}", prefix);
Ray Milkey5d406012014-04-08 14:44:41 -0700411
Jonathan Hart938a0152014-04-07 18:27:31 -0700412 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Ray Milkey5d406012014-04-08 14:44:41 -0700413
Jonathan Hart938a0152014-04-07 18:27:31 -0700414 if (rib != null && !rib.equals(update.getRibEntry())) {
415 // There was an existing nexthop for this prefix. This update supersedes that,
416 // so we need to remove the old flows for this prefix from the switches
417 _processDeletePrefix(prefix, rib);
418 }
Ray Milkey5d406012014-04-08 14:44:41 -0700419
Jonathan Hart938a0152014-04-07 18:27:31 -0700420 if (update.getRibEntry().getNextHop().equals(
421 InetAddresses.forString("0.0.0.0"))) {
422 // Route originated by SDN domain
423 // We don't handle these at the moment
424 log.debug("Own route {} to {}", prefix,
425 update.getRibEntry().getNextHop().getHostAddress());
426 return;
427 }
Ray Milkey5d406012014-04-08 14:44:41 -0700428
Jonathan Hart938a0152014-04-07 18:27:31 -0700429 _processRibAdd(update);
Ray Milkey269ffb92014-04-03 14:43:30 -0700430 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700431 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700432
Ray Milkey269ffb92014-04-03 14:43:30 -0700433 private void _processRibAdd(RibUpdate update) {
434 Prefix prefix = update.getPrefix();
435 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700436
Ray Milkey269ffb92014-04-03 14:43:30 -0700437 InetAddress dstIpAddress = rib.getNextHop();
438 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800439
Ray Milkey269ffb92014-04-03 14:43:30 -0700440 // See if we know the MAC address of the next hop
441 // TODO if we do not treat the next hop as a device in the future, we need to update this
442 // TODO: Fix the code below after deviceStorage was removed
443 /*
444 IDeviceObject nextHopDevice =
445 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700446
Ray Milkey269ffb92014-04-03 14:43:30 -0700447 if (nextHopDevice == null){
448 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
449 prefixesWaitingOnArp.put(dstIpAddress,
450 new RibUpdate(Operation.UPDATE, prefix, rib));
451 proxyArp.sendArpRequest(dstIpAddress, this, true);
452 return;
pingping-linba5c52f2014-02-11 16:52:01 -0800453
Ray Milkey269ffb92014-04-03 14:43:30 -0700454 }
455 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
456 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700457
Ray Milkey269ffb92014-04-03 14:43:30 -0700458 // Find the attachment point (egress interface) of the next hop
459 Interface egressInterface = null;
460 if (bgpPeers.containsKey(dstIpAddress)) {
461 //Route to a peer
462 log.debug("Route to peer {}", dstIpAddress);
463 BgpPeer peer = bgpPeers.get(dstIpAddress);
464 egressInterface = interfaces.get(peer.getInterfaceName());
465 } else {
466 //Route to non-peer
467 log.debug("Route to non-peer {}", dstIpAddress);
468 egressInterface = interfacePtrie.match(
469 new Prefix(dstIpAddress.getAddress(), 32));
470 if (egressInterface == null) {
471 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
472 return;
473 }
474 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700475
Ray Milkey269ffb92014-04-03 14:43:30 -0700476 if (nextHopMacAddress == null) {
477 prefixesWaitingOnArp.put(dstIpAddress,
478 new RibUpdate(Operation.UPDATE, prefix, rib));
479 proxyArp.sendArpRequest(dstIpAddress, this, true);
480 return;
481 } else {
482 if (!bgpPeers.containsKey(dstIpAddress)) {
483 //If the prefix is for a non-peer we need to ensure there's a path,
484 //and push one if there isn't.
485 Path path = pushedPaths.get(dstIpAddress);
486 if (path == null) {
487 path = new Path(egressInterface, dstIpAddress);
488 calculateAndPushPath(path, nextHopMacAddress);
489 pushedPaths.put(dstIpAddress, path);
490 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700491
Ray Milkey269ffb92014-04-03 14:43:30 -0700492 path.incrementUsers();
493 prefixToPath.put(prefix, path);
494 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700495
Ray Milkey269ffb92014-04-03 14:43:30 -0700496 //For all prefixes we need to add the first-hop mac-rewriting flows
497 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
498 }
499 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700500
Ray Milkey269ffb92014-04-03 14:43:30 -0700501 /**
502 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
503 * to all other border switches
504 */
505 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
506 MACAddress nextHopMacAddress) {
507 log.debug("Adding flows for prefix {}, next hop mac {}",
508 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700509
Ray Milkey269ffb92014-04-03 14:43:30 -0700510 FlowPath flowPath = new FlowPath();
511 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700512
Ray Milkey269ffb92014-04-03 14:43:30 -0700513 // Set flowPath FlowPathType and FlowPathUserState
514 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
515 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800516
Ray Milkey269ffb92014-04-03 14:43:30 -0700517 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
518 // only to the first-host switches
519 FlowPathFlags flowPathFlags = new FlowPathFlags();
520 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
521 flowPath.setFlowPathFlags(flowPathFlags);
pingping-linba5c52f2014-02-11 16:52:01 -0800522
Ray Milkey269ffb92014-04-03 14:43:30 -0700523 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700524 SwitchPort dstPort =
525 new SwitchPort(new Dpid(egressInterface.getDpid()),
526 new Port(egressInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800527
Ray Milkey269ffb92014-04-03 14:43:30 -0700528 // We only need one flow mod per switch, so pick one interface on each switch
529 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
530 for (Interface intf : interfaces.values()) {
531 if (!srcInterfaces.containsKey(intf.getDpid())
532 && !intf.equals(egressInterface)) {
533 srcInterfaces.put(intf.getDpid(), intf);
534 }
535 }
536 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800537
Ray Milkey269ffb92014-04-03 14:43:30 -0700538 if (egressInterface.equals(srcInterface)) {
539 continue;
540 }
pingping-linba5c52f2014-02-11 16:52:01 -0800541
Ray Milkey269ffb92014-04-03 14:43:30 -0700542 // Create flowPath FlowId
543 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800544
Ray Milkey269ffb92014-04-03 14:43:30 -0700545 // Create DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700546 SwitchPort srcPort =
547 new SwitchPort(new Dpid(srcInterface.getDpid()),
548 new Port(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800549
Ray Milkey269ffb92014-04-03 14:43:30 -0700550 DataPath dataPath = new DataPath();
551 dataPath.setSrcPort(srcPort);
552 dataPath.setDstPort(dstPort);
553 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800554
Ray Milkey269ffb92014-04-03 14:43:30 -0700555 // Create flow path matching condition(s): IPv4 Prefix
556 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700557 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700558 IPv4Net dstIPv4Net = new IPv4Net(prefix.toString());
559 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
560 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300561
Ray Milkey269ffb92014-04-03 14:43:30 -0700562 /*
563 * Create the Flow Entry Action(s): dst-MAC rewrite action
564 */
565 FlowEntryActions flowEntryActions = new FlowEntryActions();
566 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
567 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
568 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
569 flowEntryActions.addAction(flowEntryAction1);
570 flowPath.setFlowEntryActions(flowEntryActions);
pingping-linba5c52f2014-02-11 16:52:01 -0800571
Ray Milkey269ffb92014-04-03 14:43:30 -0700572 // Flow Path installation, only to first hop switches
573 // TODO: Add the flow by using the new Path Intent framework
574 /*
575 if (flowManagerService.addFlow(flowPath) == null) {
576 log.error("Failed to install flow path to the first hop for " +
577 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
578 nextHopMacAddress);
579 }
580 else {
581 log.debug("Successfully installed flow path to the first hop " +
582 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
583 nextHopMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800584
Ray Milkey269ffb92014-04-03 14:43:30 -0700585 pushedFlowIds.put(prefix, flowPath.flowId());
586 }
587 */
588 }
589 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700590
Jonathan Hart938a0152014-04-07 18:27:31 -0700591 public void processRibDelete(RibUpdate update) {
592 synchronized (this) {
593 Prefix prefix = update.getPrefix();
Ray Milkey5d406012014-04-08 14:44:41 -0700594
Jonathan Hart938a0152014-04-07 18:27:31 -0700595 if (ptree.remove(prefix, update.getRibEntry())) {
596 /*
597 * Only delete flows if an entry was actually removed from the trie.
598 * If no entry was removed, the <prefix, nexthop> wasn't there so
599 * it's probably already been removed and we don't need to do anything
600 */
601 _processDeletePrefix(prefix, update.getRibEntry());
602 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700603 }
604 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700605
Ray Milkey269ffb92014-04-03 14:43:30 -0700606 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
607 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700608
Ray Milkey269ffb92014-04-03 14:43:30 -0700609 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700610
Ray Milkey269ffb92014-04-03 14:43:30 -0700611 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
612 log.debug("Getting path for route with non-peer nexthop");
613 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700614
Ray Milkey269ffb92014-04-03 14:43:30 -0700615 if (path != null) {
616 //path could be null if we added to the Ptree but didn't push
617 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700618
Ray Milkey269ffb92014-04-03 14:43:30 -0700619 path.decrementUsers();
620 if (path.getUsers() <= 0 && !path.isPermanent()) {
621 deletePath(path);
622 pushedPaths.remove(path.getDstIpAddress());
623 }
624 }
625 }
626 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700627
Ray Milkey269ffb92014-04-03 14:43:30 -0700628 // TODO have not tested this module
629 private void deletePrefixFlows(Prefix prefix) {
630 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700631
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700632 //
633 // TODO: Delete the flow by using the new Path Intent framework
634 // NOTE: During the refactoring of the code below, if obtaining
635 // the values of the removed flowIds is needed, the first
636 // removeAll() statement should be replaced with the second removeAll()
637 // statement.
638 //
639 pushedFlowIds.removeAll(prefix);
640 /*
Ray Milkey269ffb92014-04-03 14:43:30 -0700641 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
642 for (FlowId flowId : flowIds) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700643 if (log.isTraceEnabled()) {
644 //Trace the flow status by flowPath in the switch before deleting it
645 log.trace("Pushing a DELETE flow mod to flowPath : {}",
646 flowManagerService.getFlow(flowId).toString());
647 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700648
Ray Milkey269ffb92014-04-03 14:43:30 -0700649 if( flowManagerService.deleteFlow(flowId))
650 {
651 log.debug("Successfully deleted FlowId: {}",flowId);
652 }
653 else
654 {
655 log.debug("Failed to delete FlowId: {}",flowId);
656 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700657 }
Pavlin Radoslavov3255ae52014-04-09 13:01:54 -0700658 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700659 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700660
Ray Milkey269ffb92014-04-03 14:43:30 -0700661 // TODO need to record the path and then delete here
662 private void deletePath(Path path) {
663 log.debug("Deleting flows for path to {}",
664 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700665
Ray Milkey269ffb92014-04-03 14:43:30 -0700666 // TODO need update
667 /*for (PushedFlowMod pfm : path.getFlowMods()) {
668 if (log.isTraceEnabled()) {
669 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
670 new Object[] {HexString.toHexString(pfm.getDpid()),
671 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
672 });
673 }
pingping-linba5c52f2014-02-11 16:52:01 -0800674
Ray Milkey269ffb92014-04-03 14:43:30 -0700675 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
676 }*/
677 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700678
679
Ray Milkey269ffb92014-04-03 14:43:30 -0700680 //TODO test next-hop changes
681 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800682
Ray Milkey269ffb92014-04-03 14:43:30 -0700683 /**
684 * On startup, we need to calculate a full mesh of paths between all gateway
685 * switches
686 */
687 private void setupFullMesh() {
688 //For each border router, calculate and install a path from every other
689 //border switch to said border router. However, don't install the entry
690 //in to the first hop switch, as we need to install an entry to rewrite
691 //for each prefix received. This will be done later when prefixes have
692 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700693
Ray Milkey269ffb92014-04-03 14:43:30 -0700694 for (BgpPeer peer : bgpPeers.values()) {
695 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700696
Ray Milkey269ffb92014-04-03 14:43:30 -0700697 //We know there's not already a Path here pushed, because this is
698 //called before all other routing
699 Path path = new Path(peerInterface, peer.getIpAddress());
700 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700701
Ray Milkey269ffb92014-04-03 14:43:30 -0700702 //See if we know the MAC address of the peer. If not we can't
703 //do anything until we learn it
704 // TODO: Fix the code below after deviceStorage was removed
705 MACAddress macAddress = null;
706 /*
707 IDeviceObject nextHopDevice =
708 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
pingping-linba5c52f2014-02-11 16:52:01 -0800709
Ray Milkey269ffb92014-04-03 14:43:30 -0700710 if(nextHopDevice == null){
711 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
712 //Put in the pending paths list first
713 pathsWaitingOnArp.put(peer.getIpAddress(), path);
714 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
715 continue;
716 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700717
Ray Milkey269ffb92014-04-03 14:43:30 -0700718 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
719 */
pingping-linba5c52f2014-02-11 16:52:01 -0800720
Ray Milkey269ffb92014-04-03 14:43:30 -0700721 if (macAddress == null) {
722 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
723 //Put in the pending paths list first
724 pathsWaitingOnArp.put(peer.getIpAddress(), path);
725 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
726 continue;
727 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700728
Ray Milkey269ffb92014-04-03 14:43:30 -0700729 //If we know the MAC, lets go ahead and push the paths to this peer
730 calculateAndPushPath(path, macAddress);
731 }
732 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700733
Ray Milkey269ffb92014-04-03 14:43:30 -0700734 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
735 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700736
Ray Milkey269ffb92014-04-03 14:43:30 -0700737 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
738 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800739
Ray Milkey269ffb92014-04-03 14:43:30 -0700740 FlowPath flowPath = new FlowPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800741
Ray Milkey269ffb92014-04-03 14:43:30 -0700742 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800743
Ray Milkey269ffb92014-04-03 14:43:30 -0700744 // Set flowPath FlowPathType and FlowPathUserState
745 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
746 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800747
Ray Milkey269ffb92014-04-03 14:43:30 -0700748 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
749 FlowPathFlags flowPathFlags = new FlowPathFlags();
750 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
751 flowPath.setFlowPathFlags(flowPathFlags);
752
753 // Create the DataPath object: dstSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700754 SwitchPort dstPort =
755 new SwitchPort(new Dpid(dstInterface.getDpid()),
756 new Port(dstInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800757
Ray Milkey269ffb92014-04-03 14:43:30 -0700758 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800759
Ray Milkey269ffb92014-04-03 14:43:30 -0700760 if (dstInterface.equals(srcInterface)) {
761 continue;
762 }
pingping-linba5c52f2014-02-11 16:52:01 -0800763
Ray Milkey269ffb92014-04-03 14:43:30 -0700764 // Create flowPath FlowId
765 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800766
Ray Milkey269ffb92014-04-03 14:43:30 -0700767 // Create the DataPath object: srcSwitchPort
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700768 SwitchPort srcPort =
769 new SwitchPort(new Dpid(srcInterface.getDpid()),
770 new Port(srcInterface.getPort()));
pingping-linba5c52f2014-02-11 16:52:01 -0800771
Ray Milkey269ffb92014-04-03 14:43:30 -0700772 DataPath dataPath = new DataPath();
773 dataPath.setSrcPort(srcPort);
774 dataPath.setDstPort(dstPort);
775 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800776
Ray Milkey269ffb92014-04-03 14:43:30 -0700777 // Create the Flow Path Match condition(s)
778 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700779 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
Ray Milkey269ffb92014-04-03 14:43:30 -0700780 flowEntryMatch.enableDstMac(dstMacAddress);
781 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800782
Ray Milkey269ffb92014-04-03 14:43:30 -0700783 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
784 // Shortest Path Flow, and is always the last action for the Flow Entries
785 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
786 // TODO: Add the flow by using the new Path Intent framework
787 /*
788 if (flowManagerService.addFlow(flowPath) == null) {
789 log.error("Failed to set up MAC based forwarding path to {}, {}",
790 path.getDstIpAddress().getHostAddress(),dstMacAddress);
791 }
792 else {
793 log.debug("Successfully set up MAC based forwarding path to {}, {}",
794 path.getDstIpAddress().getHostAddress(),dstMacAddress);
795 }
796 */
797 }
798 }
pingping-linba5c52f2014-02-11 16:52:01 -0800799
Ray Milkey269ffb92014-04-03 14:43:30 -0700800 /**
Jonathan Hart938a0152014-04-07 18:27:31 -0700801 * Proactively install all BGP traffic paths from BGP host attachment point
Ray Milkey269ffb92014-04-03 14:43:30 -0700802 * in SDN network to all the virtual gateways to BGP peers in other networks
803 */
804 private void setupBgpPaths() {
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200805
Ray Milkey269ffb92014-04-03 14:43:30 -0700806 for (BgpPeer bgpPeer : bgpPeers.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800807
Ray Milkey269ffb92014-04-03 14:43:30 -0700808 FlowPath flowPath = new FlowPath();
809 flowPath.setInstallerId(new CallerId("SDNIP"));
pingping-linba5c52f2014-02-11 16:52:01 -0800810
Ray Milkey269ffb92014-04-03 14:43:30 -0700811 // Set flowPath FlowPathType and FlowPathUserState
812 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
813 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
pingping-linba5c52f2014-02-11 16:52:01 -0800814
Ray Milkey269ffb92014-04-03 14:43:30 -0700815 // Install flow paths between BGPd and its peers
816 // There is no need to set the FlowPathFlags
817 flowPath.setFlowPathFlags(new FlowPathFlags(0));
pingping-linba5c52f2014-02-11 16:52:01 -0800818
Ray Milkey269ffb92014-04-03 14:43:30 -0700819 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
pingping-linba5c52f2014-02-11 16:52:01 -0800820
Ray Milkey269ffb92014-04-03 14:43:30 -0700821 // Create the Flow Path Match condition(s)
822 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Ray Milkey5c9f2db2014-04-09 10:31:21 -0700823 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPV4);
pingping-linba5c52f2014-02-11 16:52:01 -0800824
Ray Milkey269ffb92014-04-03 14:43:30 -0700825 // Match both source address and dest address
826 IPv4Net dstIPv4Net = new IPv4Net(bgpPeer.getIpAddress().getHostAddress() + "/32");
827 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800828
Ray Milkey269ffb92014-04-03 14:43:30 -0700829 IPv4Net srcIPv4Net = new IPv4Net(peerInterface.getIpAddress().getHostAddress() + "/32");
830 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
pingping-linba5c52f2014-02-11 16:52:01 -0800831
Ray Milkey269ffb92014-04-03 14:43:30 -0700832 // Match TCP protocol
833 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
pingping-linba5c52f2014-02-11 16:52:01 -0800834
Ray Milkey269ffb92014-04-03 14:43:30 -0700835 // Match destination TCP port
836 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
837 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800838
Ray Milkey269ffb92014-04-03 14:43:30 -0700839 /**
840 * Create the DataPath: BGP -> BGP peer
841 */
842 // Flow path for src-TCP-port
843 DataPath dataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800844
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700845 SwitchPort srcPort =
846 new SwitchPort(bgpdAttachmentPoint.dpid(),
847 bgpdAttachmentPoint.port());
Ray Milkey269ffb92014-04-03 14:43:30 -0700848 dataPath.setSrcPort(srcPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800849
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700850 SwitchPort dstPort =
851 new SwitchPort(new Dpid(peerInterface.getDpid()),
852 new Port(peerInterface.getSwitchPort().port()));
Ray Milkey269ffb92014-04-03 14:43:30 -0700853 dataPath.setDstPort(dstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800854
Ray Milkey269ffb92014-04-03 14:43:30 -0700855 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800856
Ray Milkey269ffb92014-04-03 14:43:30 -0700857 // TODO: Add the flow by using the new Path Intent framework
858 /*
859 if (flowManagerService.addFlow(flowPath) == null) {
860 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
861 bgpPeer.getIpAddress().getHostAddress());
862 }
863 else {
864 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
865 bgpPeer.getIpAddress().getHostAddress());
866 }
867 */
pingping-linba5c52f2014-02-11 16:52:01 -0800868
Ray Milkey269ffb92014-04-03 14:43:30 -0700869 // Disable dst-TCP-port, and set src-TCP-port
870 flowEntryMatch.disableDstTcpUdpPort();
871 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
872 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800873
Ray Milkey269ffb92014-04-03 14:43:30 -0700874 // Create a new FlowId
875 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800876
Ray Milkey269ffb92014-04-03 14:43:30 -0700877 // TODO: Add the flow by using the new Path Intent framework
878 /*
879 if (flowManagerService.addFlow(flowPath) == null) {
880 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
881 bgpPeer.getIpAddress().getHostAddress());
882 }
883 else {
884 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
885 bgpPeer.getIpAddress().getHostAddress());
886 }
887 */
pingping-linba5c52f2014-02-11 16:52:01 -0800888
Ray Milkey269ffb92014-04-03 14:43:30 -0700889 /**
890 * Create the DataPath: BGP <-BGP peer
891 */
892 // Reversed BGP flow path for src-TCP-port
893 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800894
Ray Milkey2476cac2014-04-08 11:03:21 -0700895 DataPath reverseDataPath = new DataPath();
pingping-linba5c52f2014-02-11 16:52:01 -0800896
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700897 SwitchPort reverseDstPort =
898 new SwitchPort(bgpdAttachmentPoint.dpid(),
899 bgpdAttachmentPoint.port());
Ray Milkey2476cac2014-04-08 11:03:21 -0700900 reverseDataPath.setDstPort(reverseDstPort);
pingping-linba5c52f2014-02-11 16:52:01 -0800901
Pavlin Radoslavov29a2a882014-04-08 17:40:54 -0700902 SwitchPort reverseSrcPort =
903 new SwitchPort(new Dpid(peerInterface.getDpid()),
904 new Port(peerInterface.getSwitchPort().port()));
Ray Milkey2476cac2014-04-08 11:03:21 -0700905 reverseDataPath.setSrcPort(reverseSrcPort);
906 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800907
Jonathan Hart938a0152014-04-07 18:27:31 -0700908 // Reverse the dst IP and src IP addresses
Ray Milkey269ffb92014-04-03 14:43:30 -0700909 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
910 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
911 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800912
Ray Milkey269ffb92014-04-03 14:43:30 -0700913 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800914
Ray Milkey269ffb92014-04-03 14:43:30 -0700915 // TODO: Add the flow by using the new Path Intent framework
916 /*
917 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800918
Ray Milkey269ffb92014-04-03 14:43:30 -0700919 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
920 bgpPeer.getIpAddress().getHostAddress());
921 }
922 else {
923 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
924 bgpPeer.getIpAddress().getHostAddress());
925 }
926 */
pingping-linba5c52f2014-02-11 16:52:01 -0800927
Ray Milkey269ffb92014-04-03 14:43:30 -0700928 // Reversed BGP flow path for dst-TCP-port
929 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800930
Ray Milkey269ffb92014-04-03 14:43:30 -0700931 // Disable src-TCP-port, and set the dst-TCP-port
932 flowEntryMatch.disableSrcTcpUdpPort();
933 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
934 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800935
Ray Milkey269ffb92014-04-03 14:43:30 -0700936 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800937
Ray Milkey269ffb92014-04-03 14:43:30 -0700938 // TODO: Add the flow by using the new Path Intent framework
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 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700949
Ray Milkey269ffb92014-04-03 14:43:30 -0700950 /**
951 * ICMP paths between BGPd and its peers
952 */
Jonathan Hart938a0152014-04-07 18:27:31 -0700953 // match ICMP protocol BGP <- Peer
Ray Milkey269ffb92014-04-03 14:43:30 -0700954 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800955
Ray Milkey269ffb92014-04-03 14:43:30 -0700956 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
957 flowEntryMatch.disableSrcTcpUdpPort();
958 flowEntryMatch.disableDstTcpUdpPort();
pingping-linba5c52f2014-02-11 16:52:01 -0800959
Ray Milkey269ffb92014-04-03 14:43:30 -0700960 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800961
Ray Milkey2476cac2014-04-08 11:03:21 -0700962 flowPath.setDataPath(reverseDataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800963
Ray Milkey269ffb92014-04-03 14:43:30 -0700964 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800965
Ray Milkey269ffb92014-04-03 14:43:30 -0700966 // TODO: Add the flow by using the new Path Intent framework
967 /*
968 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800969
Ray Milkey269ffb92014-04-03 14:43:30 -0700970 log.error("Failed to set up ICMP path BGP <- Peer {}",
971 bgpPeer.getIpAddress().getHostAddress());
972 }
973 else {
974 log.debug("Successfully set up ICMP path BGP <- Peer {}",
975 bgpPeer.getIpAddress().getHostAddress());
976 }
977 */
pingping-linba5c52f2014-02-11 16:52:01 -0800978
Jonathan Hart938a0152014-04-07 18:27:31 -0700979 // match ICMP protocol BGP -> Peer
Ray Milkey269ffb92014-04-03 14:43:30 -0700980 flowPath.setFlowId(new FlowId());
pingping-linba5c52f2014-02-11 16:52:01 -0800981
Ray Milkey269ffb92014-04-03 14:43:30 -0700982 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
983 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
984 flowPath.setFlowEntryMatch(flowEntryMatch);
pingping-linba5c52f2014-02-11 16:52:01 -0800985
Ray Milkey269ffb92014-04-03 14:43:30 -0700986 flowPath.setDataPath(dataPath);
pingping-linba5c52f2014-02-11 16:52:01 -0800987
Ray Milkey269ffb92014-04-03 14:43:30 -0700988 log.debug("ICMP flowPath: {}", flowPath.toString());
pingping-linba5c52f2014-02-11 16:52:01 -0800989
Ray Milkey269ffb92014-04-03 14:43:30 -0700990 // TODO: Add the flow by using the new Path Intent framework
991 /*
992 if (flowManagerService.addFlow(flowPath) == null) {
pingping-linba5c52f2014-02-11 16:52:01 -0800993
Ray Milkey269ffb92014-04-03 14:43:30 -0700994 log.error("Failed to set up ICMP path BGP -> Peer {}",
995 bgpPeer.getIpAddress().getHostAddress());
996 }
997 else {
998 log.debug("Successfully set up ICMP path BGP -> Peer {}",
999 bgpPeer.getIpAddress().getHostAddress());
1000 }
1001 */
1002 }
1003 }
pingping-linba5c52f2014-02-11 16:52:01 -08001004
Ray Milkey269ffb92014-04-03 14:43:30 -07001005 @Override
1006 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
1007 log.debug("Received ARP response: {} => {}",
1008 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001009
Ray Milkey269ffb92014-04-03 14:43:30 -07001010 /*
1011 * We synchronize on this to prevent changes to the ptree while we're pushing
1012 * flows to the switches. If the ptree changes, the ptree and switches
1013 * could get out of sync.
1014 */
1015 synchronized (this) {
1016 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001017
Ray Milkey269ffb92014-04-03 14:43:30 -07001018 if (path != null) {
1019 log.debug("Pushing path to {} at {} on {}", new Object[]{
1020 path.getDstIpAddress().getHostAddress(), macAddress,
1021 path.getDstInterface().getSwitchPort()});
Jonathan Hart938a0152014-04-07 18:27:31 -07001022 // These paths should always be to BGP peers. Paths to non-peers are
1023 // handled once the first prefix is ready to push
Ray Milkey269ffb92014-04-03 14:43:30 -07001024 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001025 // A path already got pushed to this endpoint while we were waiting
1026 // for ARP. We'll copy over the permanent attribute if it is set on this path.
Ray Milkey269ffb92014-04-03 14:43:30 -07001027 if (path.isPermanent()) {
1028 pushedPaths.get(path.getDstIpAddress()).setPermanent();
1029 }
1030 } else {
1031 calculateAndPushPath(path, macAddress);
1032 pushedPaths.put(path.getDstIpAddress(), path);
1033 }
1034 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001035
Ray Milkey269ffb92014-04-03 14:43:30 -07001036 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001037
Ray Milkey269ffb92014-04-03 14:43:30 -07001038 for (RibUpdate update : prefixesToPush) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001039 // These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001040
Ray Milkey269ffb92014-04-03 14:43:30 -07001041 RibEntry rib = ptree.lookup(update.getPrefix());
1042 if (rib != null && rib.equals(update.getRibEntry())) {
1043 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
1044 rib.getNextHop().getHostAddress());
Jonathan Hart938a0152014-04-07 18:27:31 -07001045 // We only push prefix flows if the prefix is still in the ptree
1046 // and the next hop is the same as our update. The prefix could
1047 // have been removed while we were waiting for the ARP, or the
1048 // next hop could have changed.
Ray Milkey269ffb92014-04-03 14:43:30 -07001049 _processRibAdd(update);
1050 } else {
1051 log.debug("Received ARP response, but {},{} is no longer in ptree",
1052 update.getPrefix(), update.getRibEntry());
1053 }
1054 }
1055 }
1056 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001057
Jonathan Hart938a0152014-04-07 18:27:31 -07001058 // TODO wait the priority module of the flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001059 private void setupArpFlows() {
1060 OFMatch match = new OFMatch();
1061 match.setDataLayerType(Ethernet.TYPE_ARP);
1062 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001063
Ray Milkey269ffb92014-04-03 14:43:30 -07001064 OFFlowMod fm = new OFFlowMod();
1065 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001066
Ray Milkey269ffb92014-04-03 14:43:30 -07001067 OFActionOutput action = new OFActionOutput();
1068 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1069 action.setMaxLength((short) 0xffff);
1070 List<OFAction> actions = new ArrayList<OFAction>(1);
1071 actions.add(action);
1072 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001073
Ray Milkey269ffb92014-04-03 14:43:30 -07001074 fm.setIdleTimeout((short) 0)
1075 .setHardTimeout((short) 0)
1076 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1077 .setCookie(0)
1078 .setCommand(OFFlowMod.OFPFC_ADD)
1079 .setPriority(ARP_PRIORITY)
1080 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001081
Ray Milkey269ffb92014-04-03 14:43:30 -07001082 for (String strdpid : switches) {
1083 flowCache.write(HexString.toLong(strdpid), fm);
1084 }
1085 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001086
Jonathan Hart938a0152014-04-07 18:27:31 -07001087 // TODO need update, waiting for the priority feature from flow Manager
Ray Milkey269ffb92014-04-03 14:43:30 -07001088 private void setupDefaultDropFlows() {
1089 OFFlowMod fm = new OFFlowMod();
1090 fm.setMatch(new OFMatch());
Jonathan Hart938a0152014-04-07 18:27:31 -07001091 fm.setActions(new ArrayList<OFAction>()); // No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001092
Ray Milkey269ffb92014-04-03 14:43:30 -07001093 fm.setIdleTimeout((short) 0)
1094 .setHardTimeout((short) 0)
1095 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1096 .setCookie(0)
1097 .setCommand(OFFlowMod.OFPFC_ADD)
1098 .setPriority((short) 0)
1099 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001100
Ray Milkey269ffb92014-04-03 14:43:30 -07001101 OFFlowMod fmLLDP;
1102 OFFlowMod fmBDDP;
1103 try {
1104 fmLLDP = fm.clone();
1105 fmBDDP = fm.clone();
1106 } catch (CloneNotSupportedException e1) {
1107 log.error("Error cloning flow mod", e1);
1108 return;
1109 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001110
Ray Milkey269ffb92014-04-03 14:43:30 -07001111 OFMatch matchLLDP = new OFMatch();
1112 matchLLDP.setDataLayerType((short) 0x88cc);
1113 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1114 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001115
Ray Milkey269ffb92014-04-03 14:43:30 -07001116 OFMatch matchBDDP = new OFMatch();
1117 matchBDDP.setDataLayerType((short) 0x8942);
1118 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1119 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001120
Ray Milkey269ffb92014-04-03 14:43:30 -07001121 OFActionOutput action = new OFActionOutput();
1122 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1123 action.setMaxLength((short) 0xffff);
1124 List<OFAction> actions = new ArrayList<OFAction>(1);
1125 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001126
Ray Milkey269ffb92014-04-03 14:43:30 -07001127 fmLLDP.setActions(actions);
1128 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001129
Ray Milkey269ffb92014-04-03 14:43:30 -07001130 fmLLDP.setPriority(ARP_PRIORITY);
1131 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1132 fmBDDP.setPriority(ARP_PRIORITY);
1133 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001134
Ray Milkey269ffb92014-04-03 14:43:30 -07001135 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1136 flowModList.add(fm);
1137 flowModList.add(fmLLDP);
1138 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001139
Ray Milkey269ffb92014-04-03 14:43:30 -07001140 for (String strdpid : switches) {
1141 flowCache.write(HexString.toLong(strdpid), flowModList);
1142 }
1143 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001144
Ray Milkey269ffb92014-04-03 14:43:30 -07001145 private void beginRouting() {
1146 log.debug("Topology is now ready, beginning routing function");
1147 // TODO: Fix for the new Topology Network Graph
1148 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001149
Ray Milkey269ffb92014-04-03 14:43:30 -07001150 // Wait Pavlin's API. We need the following functions.
1151 /*setupArpFlows();
1152 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001153
Ray Milkey269ffb92014-04-03 14:43:30 -07001154 setupBgpPaths();
1155 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001156
Ray Milkey269ffb92014-04-03 14:43:30 -07001157 //Suppress link discovery on external-facing router ports
1158 for (Interface intf : interfaces.values()) {
1159 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1160 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001161
Ray Milkey269ffb92014-04-03 14:43:30 -07001162 bgpUpdatesExecutor.execute(new Runnable() {
1163 @Override
1164 public void run() {
1165 doUpdatesThread();
1166 }
1167 });
1168 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001169
Jonathan Hart938a0152014-04-07 18:27:31 -07001170 // Before inserting the paths for BGP traffic, we should check whether
1171 // all the switches in the configuration file are discovered by ONOS
Ray Milkey269ffb92014-04-03 14:43:30 -07001172 private void checkSwitchesConnected() {
Jonathan Hart938a0152014-04-07 18:27:31 -07001173 // TODO: Fix the code below after topoSwitchSerice was removed
1174 /*
Ray Milkey269ffb92014-04-03 14:43:30 -07001175 for (String dpid : switches) {
Ray Milkey5d406012014-04-08 14:44:41 -07001176
Ray Milkey269ffb92014-04-03 14:43:30 -07001177 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1178 getActiveSwitches().iterator();
1179 while(activeSwitches.hasNext())
1180 {
1181 ISwitchObject switchObject = activeSwitches.next();
1182 if (switchObject.getDPID().equals(dpid)) {
1183 break;
1184 }
1185 if(activeSwitches.hasNext() == false) {
1186 log.debug("Not all switches are here yet");
1187 return;
1188 }
1189 }
Ray Milkey269ffb92014-04-03 14:43:30 -07001190 }
1191 switchesConnected = true;
Jonathan Hart938a0152014-04-07 18:27:31 -07001192 */
Ray Milkey269ffb92014-04-03 14:43:30 -07001193 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001194
Jonathan Hart938a0152014-04-07 18:27:31 -07001195 // Actually we only need to go half way round to verify full mesh connectivity
Ray Milkey269ffb92014-04-03 14:43:30 -07001196 private void checkTopologyReady() {
1197 for (Interface dstInterface : interfaces.values()) {
1198 for (Interface srcInterface : interfaces.values()) {
1199 if (dstInterface.equals(srcInterface)) {
1200 continue;
1201 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001202
Ray Milkey269ffb92014-04-03 14:43:30 -07001203 // TODO: Fix for the new Topology Network Graph
1204 /*
1205 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
1206 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001207
Ray Milkey269ffb92014-04-03 14:43:30 -07001208 if (shortestPath == null){
1209 log.debug("Shortest path between {} and {} not found",
1210 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
1211 return;
1212 }
1213 */
1214 }
1215 }
1216 topologyReady = true;
1217 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001218
Ray Milkey269ffb92014-04-03 14:43:30 -07001219 private void checkStatus() {
1220 if (!switchesConnected) {
1221 checkSwitchesConnected();
1222 }
1223 boolean oldTopologyReadyStatus = topologyReady;
1224 if (switchesConnected && !topologyReady) {
1225 checkTopologyReady();
1226 }
1227 if (!oldTopologyReadyStatus && topologyReady) {
1228 beginRouting();
1229 }
1230 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001231
Ray Milkey269ffb92014-04-03 14:43:30 -07001232 private void doUpdatesThread() {
1233 boolean interrupted = false;
1234 try {
1235 while (true) {
1236 try {
1237 RibUpdate update = ribUpdates.take();
1238 switch (update.getOperation()) {
1239 case UPDATE:
1240 if (validateUpdate(update)) {
1241 processRibAdd(update);
1242 } else {
1243 log.debug("Rib UPDATE out of order: {} via {}",
1244 update.getPrefix(), update.getRibEntry().getNextHop());
1245 }
1246 break;
1247 case DELETE:
1248 if (validateUpdate(update)) {
1249 processRibDelete(update);
1250 } else {
1251 log.debug("Rib DELETE out of order: {} via {}",
1252 update.getPrefix(), update.getRibEntry().getNextHop());
1253 }
1254 break;
1255 }
1256 } catch (InterruptedException e) {
1257 log.debug("Interrupted while taking from updates queue", e);
1258 interrupted = true;
1259 } catch (Exception e) {
1260 log.debug("exception", e);
1261 }
1262 }
1263 } finally {
1264 if (interrupted) {
1265 Thread.currentThread().interrupt();
1266 }
1267 }
1268 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001269
Ray Milkey269ffb92014-04-03 14:43:30 -07001270 private boolean validateUpdate(RibUpdate update) {
1271 RibEntry newEntry = update.getRibEntry();
1272 RibEntry oldEntry = ptree.lookup(update.getPrefix());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001273
Ray Milkey269ffb92014-04-03 14:43:30 -07001274 //If there is no existing entry we must assume this is the most recent
1275 //update. However this might not always be the case as we might have a
1276 //POST then DELETE reordering.
1277 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1278 if (oldEntry == null) {
1279 return true;
1280 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001281
Ray Milkey269ffb92014-04-03 14:43:30 -07001282 // This handles the case where routes are gathered in the initial
1283 // request because they don't have sequence number info
1284 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1285 return true;
1286 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001287
Ray Milkey269ffb92014-04-03 14:43:30 -07001288 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1289 return true;
1290 } else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1291 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1292 return true;
1293 } else {
1294 return false;
1295 }
1296 } else {
1297 return false;
1298 }
1299 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001300
Ray Milkey269ffb92014-04-03 14:43:30 -07001301 // The code below should be reimplemented after removal of Floodlight's
1302 // ITopologyService API. It should be implemented on top of network graph
1303 // notifications. (It was pretty hacky anyway...)
1304 /*
1305 @Override
1306 public void topologyChanged() {
1307 if (topologyReady) {
1308 return;
1309 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001310
Ray Milkey269ffb92014-04-03 14:43:30 -07001311 boolean refreshNeeded = false;
1312 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
1313 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1314 //We don't need to recalculate anything for just link updates
1315 //They happen very frequently
1316 refreshNeeded = true;
1317 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001318
Ray Milkey269ffb92014-04-03 14:43:30 -07001319 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001320
Ray Milkey269ffb92014-04-03 14:43:30 -07001321 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1322 synchronized (linkUpdates) {
1323 linkUpdates.add(ldu);
1324 }
1325 }
1326 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001327
Ray Milkey269ffb92014-04-03 14:43:30 -07001328 if (refreshNeeded && !topologyReady){
1329 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
1330 }
1331 }
1332 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001333
Ray Milkey269ffb92014-04-03 14:43:30 -07001334 @Override
1335 public void addedSwitch(IOFSwitch sw) {
1336 if (!topologyReady) {
1337 sw.clearAllFlowMods();
1338 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001339
Ray Milkey269ffb92014-04-03 14:43:30 -07001340 flowCache.switchConnected(sw);
1341 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001342
Ray Milkey269ffb92014-04-03 14:43:30 -07001343 @Override
1344 public void removedSwitch(IOFSwitch sw) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001345 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001346 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001347
Ray Milkey269ffb92014-04-03 14:43:30 -07001348 @Override
1349 public void switchPortChanged(Long switchId) {
Jonathan Hart938a0152014-04-07 18:27:31 -07001350 // Not used
Ray Milkey269ffb92014-04-03 14:43:30 -07001351 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001352
Ray Milkey269ffb92014-04-03 14:43:30 -07001353 @Override
1354 public String getName() {
1355 return "BgpRoute";
1356 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001357
Ray Milkey269ffb92014-04-03 14:43:30 -07001358 /*
1359 * IConfigInfoService methods
1360 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001361
Ray Milkey269ffb92014-04-03 14:43:30 -07001362 @Override
1363 public boolean isInterfaceAddress(InetAddress address) {
1364 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1365 return (intf != null && intf.getIpAddress().equals(address));
1366 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001367
Ray Milkey269ffb92014-04-03 14:43:30 -07001368 @Override
1369 public boolean inConnectedNetwork(InetAddress address) {
1370 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1371 return (intf != null && !intf.getIpAddress().equals(address));
1372 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001373
Ray Milkey269ffb92014-04-03 14:43:30 -07001374 @Override
1375 public boolean fromExternalNetwork(long inDpid, short inPort) {
1376 for (Interface intf : interfaces.values()) {
1377 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1378 return true;
1379 }
1380 }
1381 return false;
1382 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001383
Ray Milkey269ffb92014-04-03 14:43:30 -07001384 @Override
1385 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1386 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1387 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001388
Ray Milkey269ffb92014-04-03 14:43:30 -07001389 @Override
1390 public boolean hasLayer3Configuration() {
1391 return !interfaces.isEmpty();
1392 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001393
Ray Milkey269ffb92014-04-03 14:43:30 -07001394 @Override
1395 public MACAddress getRouterMacAddress() {
1396 return bgpdMacAddress;
1397 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001398
Ray Milkey269ffb92014-04-03 14:43:30 -07001399 @Override
1400 public short getVlan() {
1401 return vlan;
1402 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001403}