blob: a6aacf1420c3b0c35edea7d14025d7c70092491a [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.INetMapTopologyObjects.IDeviceObject;
37import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
Jonathan Hartebba1e12013-10-29 11:37:02 -070038import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070039import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
40import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harte7694532013-09-12 12:34:46 +120041import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120042import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
pingping-linba5c52f2014-02-11 16:52:01 -080043import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
pingping-linba5c52f2014-02-11 16:52:01 -080044import net.onrc.onos.ofcontroller.util.CallerId;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070045import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120046import net.onrc.onos.ofcontroller.util.Dpid;
pingping-linba5c52f2014-02-11 16:52:01 -080047import net.onrc.onos.ofcontroller.util.FlowEntryAction;
48import net.onrc.onos.ofcontroller.util.FlowEntryActions;
49import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
50import net.onrc.onos.ofcontroller.util.FlowId;
51import net.onrc.onos.ofcontroller.util.FlowPath;
52import net.onrc.onos.ofcontroller.util.FlowPathFlags;
53import net.onrc.onos.ofcontroller.util.FlowPathType;
54import net.onrc.onos.ofcontroller.util.FlowPathUserState;
55import net.onrc.onos.ofcontroller.util.IPv4Net;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070056import net.onrc.onos.ofcontroller.util.Port;
57import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080058import net.sf.json.JSONArray;
59import net.sf.json.JSONObject;
60import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080061
Jonathan Hartd1f23252013-06-13 15:17:05 +120062import org.codehaus.jackson.JsonParseException;
63import org.codehaus.jackson.map.JsonMappingException;
64import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070065import org.openflow.protocol.OFFlowMod;
66import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070067import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120068import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070069import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070070import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120071import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080072import org.slf4j.Logger;
73import org.slf4j.LoggerFactory;
74
Jonathan Hart4dfc3652013-08-02 20:22:36 +120075import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120076import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120077import com.google.common.collect.Multimaps;
78import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120079import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120080import com.google.common.util.concurrent.ThreadFactoryBuilder;
81
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070082public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120083 ITopologyListener, IArpRequester,
Jonathan Hart7804bea2014-01-07 10:50:52 -080084 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070085
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070086 private final static Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080087
Jonathan Hartf247ee72013-10-18 18:57:28 -070088 private IFloodlightProviderService floodlightProvider;
Jonathan Hart3a326122013-10-21 11:51:13 -070089 private ITopologyService topologyService;
Jonathan Hartf247ee72013-10-18 18:57:28 -070090 private ILinkDiscoveryService linkDiscoveryService;
91 private IRestApiService restApi;
pingping-linba5c52f2014-02-11 16:52:01 -080092 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070093
Jonathan Hartf247ee72013-10-18 18:57:28 -070094 private IPatriciaTrie<RibEntry> ptree;
95 private IPatriciaTrie<Interface> interfacePtrie;
96 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070097
Jonathan Hartf247ee72013-10-18 18:57:28 -070098 private String bgpdRestIp;
99 private String routerId;
100 private String configFilename = "config.json";
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700101
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700102 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
103 //the controller/OS should hand out cookie IDs to prevent conflicts.
Jonathan Hartf247ee72013-10-18 18:57:28 -0700104 private final long APP_COOKIE = 0xa0000000000000L;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700105 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Jonathan Hartf247ee72013-10-18 18:57:28 -0700106 private final long L2_FWD_COOKIE = APP_COOKIE + 1;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700107 //Cookie for flows in ingress switches that rewrite the MAC address
Jonathan Hartf247ee72013-10-18 18:57:28 -0700108 private final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200109 //Cookie for flows that setup BGP paths
Jonathan Hartf247ee72013-10-18 18:57:28 -0700110 private final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200111 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
112 //need to be higher priority than this otherwise the rewrite may not get done
Jonathan Hartf247ee72013-10-18 18:57:28 -0700113 private final short SDNIP_PRIORITY = 10;
114 private final short ARP_PRIORITY = 20;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700115
Jonathan Hartf247ee72013-10-18 18:57:28 -0700116 private final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700117
Jonathan Hartf247ee72013-10-18 18:57:28 -0700118 private final int TOPO_DETECTION_WAIT = 2; //seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700119
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200120 //Configuration stuff
Jonathan Hartf247ee72013-10-18 18:57:28 -0700121 private List<String> switches;
122 private Map<String, Interface> interfaces;
123 private Map<InetAddress, BgpPeer> bgpPeers;
124 private SwitchPort bgpdAttachmentPoint;
125 private MACAddress bgpdMacAddress;
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700126 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700127
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200128 //True when all switches have connected
Jonathan Hartf247ee72013-10-18 18:57:28 -0700129 private volatile boolean switchesConnected = false;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200130 //True when we have a full mesh of shortest paths between gateways
Jonathan Hartf247ee72013-10-18 18:57:28 -0700131 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200132
Jonathan Hartf247ee72013-10-18 18:57:28 -0700133 private ArrayList<LDUpdate> linkUpdates;
134 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700135
Jonathan Hartf247ee72013-10-18 18:57:28 -0700136 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700137
Jonathan Hartf247ee72013-10-18 18:57:28 -0700138 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700139
Jonathan Hartf247ee72013-10-18 18:57:28 -0700140 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700141
Jonathan Hartf247ee72013-10-18 18:57:28 -0700142 private Map<InetAddress, Path> pushedPaths;
143 private Map<Prefix, Path> prefixToPath;
pingping-linba5c52f2014-02-11 16:52:01 -0800144// private Multimap<Prefix, PushedFlowMod> pushedFlows;
145 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700146
Jonathan Hart1912afc2013-10-11 12:02:44 +1300147 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700148
Pavlin Radoslavov1237e392014-03-20 16:24:06 -0700149 // TODO: Fix for the new Topology Network Graph
150 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700151
Jonathan Hartf247ee72013-10-18 18:57:28 -0700152 private class TopologyChangeDetector implements Runnable {
Jonathan Hart98957bf2013-07-01 14:49:24 +1200153 @Override
154 public void run() {
155 log.debug("Running topology change detection task");
156 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200157 //This is the model the REST API uses to retrieve network graph info
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700158 // TODO: Fix the code below after topoLinkService was removed
159 /*
Jonathan Hart98957bf2013-07-01 14:49:24 +1200160 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700161
Jonathan Hart98957bf2013-07-01 14:49:24 +1200162 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700163
Jonathan Hart98957bf2013-07-01 14:49:24 +1200164 Iterator<LDUpdate> it = linkUpdates.iterator();
165 while (it.hasNext()){
166 LDUpdate ldu = it.next();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700167 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
Jonathan Hart98957bf2013-07-01 14:49:24 +1200168 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700169
Jonathan Hart98957bf2013-07-01 14:49:24 +1200170 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200171 it.remove();
172 }
173 }
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700174 */
Jonathan Hart98957bf2013-07-01 14:49:24 +1200175 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700176
Jonathan Hart64c0b202013-08-20 15:45:07 +1200177 if (!topologyReady) {
178 if (linkUpdates.isEmpty()){
179 //All updates have been seen in network map.
180 //We can check if topology is ready
181 log.debug("No known changes outstanding. Checking topology now");
182 checkStatus();
183 }
184 else {
185 //We know of some link updates that haven't propagated to the database yet
186 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
187 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
188 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200189 }
190 }
191 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700192
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700193 private void readConfiguration(String configFilename){
194 File gatewaysFile = new File(configFilename);
Jonathan Hartd1f23252013-06-13 15:17:05 +1200195 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700196
Jonathan Hartd1f23252013-06-13 15:17:05 +1200197 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200198 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700199
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200200 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200201 interfaces = new HashMap<String, Interface>();
202 for (Interface intf : config.getInterfaces()){
203 interfaces.put(intf.getName(), intf);
204 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200205 bgpPeers = new HashMap<InetAddress, BgpPeer>();
206 for (BgpPeer peer : config.getPeers()){
207 bgpPeers.put(peer.getIpAddress(), peer);
208 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700209
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200210 bgpdAttachmentPoint = new SwitchPort(
211 new Dpid(config.getBgpdAttachmentDpid()),
212 new Port(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700213
Jonathan Hart2f790d22013-08-15 14:01:24 +1200214 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700215 vlan = config.getVlan();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200216 } catch (JsonParseException e) {
217 log.error("Error in JSON file", e);
218 System.exit(1);
219 } catch (JsonMappingException e) {
220 log.error("Error in JSON file", e);
221 System.exit(1);
222 } catch (IOException e) {
223 log.error("Error reading JSON file", e);
224 System.exit(1);
225 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700226
Jonathan Hartabf10222013-08-13 10:19:34 +1200227 //Populate the interface Patricia Trie
228 for (Interface intf : interfaces.values()) {
229 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
230 interfacePtrie.put(prefix, intf);
231 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700232 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700233
pingping-lina2cbfad2013-03-07 08:39:21 +0800234 @Override
235 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700236 Collection<Class<? extends IFloodlightService>> l
Jonathan Hart61ba9372013-05-19 20:10:29 -0700237 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800238 l.add(IBgpRouteService.class);
Jonathan Harta8887642013-10-28 13:46:54 -0700239 l.add(IConfigInfoService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800240 return l;
241 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700242
pingping-lina2cbfad2013-03-07 08:39:21 +0800243 @Override
244 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700245 Map<Class<? extends IFloodlightService>, IFloodlightService> m
Jonathan Hart61ba9372013-05-19 20:10:29 -0700246 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800247 m.put(IBgpRouteService.class, this);
Jonathan Harta8887642013-10-28 13:46:54 -0700248 m.put(IConfigInfoService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800249 return m;
250 }
251
pingping-lina2cbfad2013-03-07 08:39:21 +0800252 @Override
253 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700254 Collection<Class<? extends IFloodlightService>> l
Jonathan Hart61ba9372013-05-19 20:10:29 -0700255 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800256 l.add(IFloodlightProviderService.class);
257 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700258 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800259 return l;
260 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700261
pingping-lina2cbfad2013-03-07 08:39:21 +0800262 @Override
263 public void init(FloodlightModuleContext context)
264 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700265
Jonathan Hart29b972d2013-08-12 23:43:51 +1200266 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200267 interfacePtrie = new PatriciaTrie<Interface>(32);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700268
pingping-linba5c52f2014-02-11 16:52:01 -0800269 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700270
pingping-lina2cbfad2013-03-07 08:39:21 +0800271 // Register floodlight provider and REST handler.
272 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700273 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200274 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200275 restApi = context.getServiceImpl(IRestApiService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800276 proxyArp = context.getServiceImpl(IProxyArpService.class);
277
Jonathan Hart98957bf2013-07-01 14:49:24 +1200278 linkUpdates = new ArrayList<LDUpdate>();
279 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
280 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700281
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200282 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200283 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
284 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700285
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200286 pushedPaths = new HashMap<InetAddress, Path>();
287 prefixToPath = new HashMap<Prefix, Path>();
pingping-linba5c52f2014-02-11 16:52:01 -0800288// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
289 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700290
Jonathan Hart1912afc2013-10-11 12:02:44 +1300291 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700292
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200293 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
294 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700295
Jonathan Hart61ba9372013-05-19 20:10:29 -0700296 //Read in config values
297 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
298 if (bgpdRestIp == null){
299 log.error("BgpdRestIp property not found in config file");
300 System.exit(1);
301 }
302 else {
303 log.info("BgpdRestIp set to {}", bgpdRestIp);
304 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700305
Jonathan Hart61ba9372013-05-19 20:10:29 -0700306 routerId = context.getConfigParams(this).get("RouterId");
307 if (routerId == null){
308 log.error("RouterId property not found in config file");
309 System.exit(1);
310 }
311 else {
312 log.info("RouterId set to {}", routerId);
313 }
pingping-linba5c52f2014-02-11 16:52:01 -0800314
Jonathan Hart9575cb62013-07-05 13:43:49 +1200315 String configFilenameParameter = context.getConfigParams(this).get("configfile");
316 if (configFilenameParameter != null){
317 configFilename = configFilenameParameter;
318 }
319 log.debug("Config file set to {}", configFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700320
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700321 readConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200322 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700323
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200324 @Override
325 public void startUp(FloodlightModuleContext context) {
326 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700327 topologyService.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200328 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800329
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200330 //Retrieve the RIB from BGPd during startup
331 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800332 }
333
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700334 @Override
Jonathan Hart29b972d2013-08-12 23:43:51 +1200335 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800336 return ptree;
337 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700338
339 @Override
Jonathan Hart61ba9372013-05-19 20:10:29 -0700340 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200341 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800342 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700343
344 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800345 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700346 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800347 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700348
349 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800350 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700351 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800352 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700353
Jonathan Hart61ba9372013-05-19 20:10:29 -0700354 private void retrieveRib(){
355 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
356 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700357
Jonathan Hart61ba9372013-05-19 20:10:29 -0700358 if (response.equals("")){
359 return;
360 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700361
Jonathan Hart61ba9372013-05-19 20:10:29 -0700362 response = response.replaceAll("\"", "'");
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700363 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700364 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
365 String router_id = jsonObj.getString("router-id");
366
367 int size = rib_json_array.size();
368
369 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700370
Jonathan Hart61ba9372013-05-19 20:10:29 -0700371 for (int j = 0; j < size; j++) {
372 JSONObject second_json_object = rib_json_array.getJSONObject(j);
373 String prefix = second_json_object.getString("prefix");
374 String nexthop = second_json_object.getString("nexthop");
375
376 //insert each rib entry into the local rib;
377 String[] substring = prefix.split("/");
378 String prefix1 = substring[0];
379 String mask1 = substring[1];
380
381 Prefix p;
382 try {
383 p = new Prefix(prefix1, Integer.valueOf(mask1));
384 } catch (NumberFormatException e) {
385 log.warn("Wrong mask format in RIB JSON: {}", mask1);
386 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200387 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700388 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
389 continue;
390 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700391
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200392 RibEntry rib = new RibEntry(router_id, nexthop);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700393
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200394 try {
395 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
396 } catch (InterruptedException e) {
397 log.debug("Interrupted while pushing onto update queue");
398 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700399 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700400 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700401
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200402 @Override
403 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200404 try {
405 ribUpdates.put(update);
406 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200407 log.debug("Interrupted while putting on ribUpdates queue", e);
408 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200409 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200410 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700411
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200412 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200413 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700414
Jonathan Hart9ea31212013-08-12 21:40:34 +1200415 log.debug("Processing prefix add {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700416
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200417 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700418
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200419 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200420 //There was an existing nexthop for this prefix. This update supersedes that,
421 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200422 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200423 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700424
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200425 if (update.getRibEntry().getNextHop().equals(
426 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200427 //Route originated by SDN domain
428 //We don't handle these at the moment
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700429 log.debug("Own route {} to {}", prefix,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200430 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200431 return;
432 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700433
Jonathan Hart309889c2013-08-13 23:26:24 +1200434 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200435 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700436
Jonathan Hart309889c2013-08-13 23:26:24 +1200437 private void _processRibAdd(RibUpdate update) {
438 Prefix prefix = update.getPrefix();
439 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700440
Jonathan Hart309889c2013-08-13 23:26:24 +1200441 InetAddress dstIpAddress = rib.getNextHop();
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700442 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800443
444 // See if we know the MAC address of the next hop
445 // TODO if we do not treat the next hop as a device in the future, we need to update this
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700446 // TODO: Fix the code below after deviceStorage was removed
447 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800448 IDeviceObject nextHopDevice =
449 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700450
pingping-linba5c52f2014-02-11 16:52:01 -0800451 if (nextHopDevice == null){
452 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
453 prefixesWaitingOnArp.put(dstIpAddress,
454 new RibUpdate(Operation.UPDATE, prefix, rib));
455 proxyArp.sendArpRequest(dstIpAddress, this, true);
456 return;
457
458 }
459 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700460 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700461
pingping-linba5c52f2014-02-11 16:52:01 -0800462 // Find the attachment point (egress interface) of the next hop
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200463 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200464 if (bgpPeers.containsKey(dstIpAddress)) {
465 //Route to a peer
466 log.debug("Route to peer {}", dstIpAddress);
467 BgpPeer peer = bgpPeers.get(dstIpAddress);
468 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200469 }
470 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200471 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200472 log.debug("Route to non-peer {}", dstIpAddress);
473 egressInterface = interfacePtrie.match(
474 new Prefix(dstIpAddress.getAddress(), 32));
475 if (egressInterface == null) {
476 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
477 return;
478 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200479 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700480
Jonathan Hart309889c2013-08-13 23:26:24 +1200481 if (nextHopMacAddress == null) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700482 prefixesWaitingOnArp.put(dstIpAddress,
Jonathan Hart309889c2013-08-13 23:26:24 +1200483 new RibUpdate(Operation.UPDATE, prefix, rib));
484 proxyArp.sendArpRequest(dstIpAddress, this, true);
485 return;
486 }
487 else {
488 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200489 //If the prefix is for a non-peer we need to ensure there's a path,
490 //and push one if there isn't.
491 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200492 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200493 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300494 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200495 pushedPaths.put(dstIpAddress, path);
496 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700497
Jonathan Hart309889c2013-08-13 23:26:24 +1200498 path.incrementUsers();
499 prefixToPath.put(prefix, path);
500 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700501
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200502 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200503 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
504 }
505 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700506
pingping-linba5c52f2014-02-11 16:52:01 -0800507 /**
508 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
509 * to all other border switches
510 */
511 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
512 MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700513 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300514 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700515
pingping-linba5c52f2014-02-11 16:52:01 -0800516 FlowPath flowPath = new FlowPath();
517 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700518
pingping-linba5c52f2014-02-11 16:52:01 -0800519 // Set flowPath FlowPathType and FlowPathUserState
520 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
521 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
522
523 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
524 // only to the first-host switches
525 FlowPathFlags flowPathFlags = new FlowPathFlags();
526 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
527 flowPath.setFlowPathFlags(flowPathFlags);
528
529 // Create the DataPath object: dstSwitchPort
530 SwitchPort dstPort = new SwitchPort();
531 dstPort.setDpid(new Dpid(egressInterface.getDpid()));
532 dstPort.setPort(new Port(egressInterface.getPort()));
533
534 // We only need one flow mod per switch, so pick one interface on each switch
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200535 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
536 for (Interface intf : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700537 if (!srcInterfaces.containsKey(intf.getDpid())
Jonathan Hart45107222013-10-22 17:35:04 -0700538 && !intf.equals(egressInterface)) {
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200539 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200540 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200541 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200542 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800543
544 if (egressInterface.equals(srcInterface)){
545 continue;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200546 }
pingping-linba5c52f2014-02-11 16:52:01 -0800547
548 // Create flowPath FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800549 flowPath.setFlowId(new FlowId());
550
551 // Create DataPath object: srcSwitchPort
552 SwitchPort srcPort = new SwitchPort();
553 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
554 srcPort.setPort(new Port(srcInterface.getPort()));
555
556 DataPath dataPath = new DataPath();
557 dataPath.setSrcPort(srcPort);
558 dataPath.setDstPort(dstPort);
559 flowPath.setDataPath(dataPath);
560
561 // Create flow path matching condition(s): IPv4 Prefix
562 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
563 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
564 IPv4Net dstIPv4Net= new IPv4Net(prefix.toString());
565 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
566 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300567
568 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800569 * Create the Flow Entry Action(s): dst-MAC rewrite action
Jonathan Hart1912afc2013-10-11 12:02:44 +1300570 */
pingping-linba5c52f2014-02-11 16:52:01 -0800571 FlowEntryActions flowEntryActions = new FlowEntryActions();
572 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
573 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
574 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
575 flowEntryActions.addAction(flowEntryAction1);
576 flowPath.setFlowEntryActions(flowEntryActions);
577
578 // Flow Path installation, only to first hop switches
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700579 // TODO: Add the flow by using the new Path Intent framework
580 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800581 if (flowManagerService.addFlow(flowPath) == null) {
582 log.error("Failed to install flow path to the first hop for " +
583 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
584 nextHopMacAddress);
585 }
586 else {
587 log.debug("Successfully installed flow path to the first hop " +
588 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
589 nextHopMacAddress);
590
591 pushedFlowIds.put(prefix, flowPath.flowId());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200592 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700593 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200594 }
595 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700596
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200597 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200598 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700599
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200600 if (ptree.remove(prefix, update.getRibEntry())) {
601 /*
602 * Only delete flows if an entry was actually removed from the trie.
603 * If no entry was removed, the <prefix, nexthop> wasn't there so
604 * it's probably already been removed and we don't need to do anything
605 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200606 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200607 }
608 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700609
Jonathan Hart309889c2013-08-13 23:26:24 +1200610 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
611 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700612
Jonathan Hart309889c2013-08-13 23:26:24 +1200613 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700614
Jonathan Hart309889c2013-08-13 23:26:24 +1200615 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
616 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200617 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700618
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200619 if (path != null) {
620 //path could be null if we added to the Ptree but didn't push
621 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700622
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200623 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200624 if (path.getUsers() <= 0 && !path.isPermanent()) {
625 deletePath(path);
626 pushedPaths.remove(path.getDstIpAddress());
627 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200628 }
629 }
630 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700631
pingping-linba5c52f2014-02-11 16:52:01 -0800632 // TODO have not tested this module
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200633 private void deletePrefixFlows(Prefix prefix) {
634 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700635
pingping-linba5c52f2014-02-11 16:52:01 -0800636 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
637 for (FlowId flowId : flowIds) {
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700638 // TODO: Delete the flow by using the new Path Intent framework
639 /*
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200640 if (log.isTraceEnabled()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800641 //Trace the flow status by flowPath in the switch before deleting it
642 log.trace("Pushing a DELETE flow mod to flowPath : {}",
643 flowManagerService.getFlow(flowId).toString());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200644 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700645
pingping-linba5c52f2014-02-11 16:52:01 -0800646 if( flowManagerService.deleteFlow(flowId))
647 {
648 log.debug("Successfully deleted FlowId: {}",flowId);
649 }
650 else
651 {
652 log.debug("Failed to delete FlowId: {}",flowId);
653 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700654 */
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200655 }
656 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700657
pingping-linba5c52f2014-02-11 16:52:01 -0800658 // TODO need to record the path and then delete here
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200659 private void deletePath(Path path) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700660 log.debug("Deleting flows for path to {}",
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200661 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700662
pingping-linba5c52f2014-02-11 16:52:01 -0800663 // TODO need update
664 /*for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200665 if (log.isTraceEnabled()) {
666 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
667 new Object[] {HexString.toHexString(pfm.getDpid()),
668 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
669 });
670 }
pingping-linba5c52f2014-02-11 16:52:01 -0800671
Jonathan Hart309889c2013-08-13 23:26:24 +1200672 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
pingping-linba5c52f2014-02-11 16:52:01 -0800673 }*/
Jonathan Hart309889c2013-08-13 23:26:24 +1200674 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700675
676
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200677 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200678 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800679
680 /**
681 * On startup, we need to calculate a full mesh of paths between all gateway
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700682 * switches
683 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200684 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700685 //For each border router, calculate and install a path from every other
686 //border switch to said border router. However, don't install the entry
687 //in to the first hop switch, as we need to install an entry to rewrite
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700688 //for each prefix received. This will be done later when prefixes have
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700689 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700690
Jonathan Hartc824ad02013-07-03 15:58:45 +1200691 for (BgpPeer peer : bgpPeers.values()) {
692 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700693
Jonathan Hart309889c2013-08-13 23:26:24 +1200694 //We know there's not already a Path here pushed, because this is
695 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200696 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200697 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700698
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200699 //See if we know the MAC address of the peer. If not we can't
700 //do anything until we learn it
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700701 // TODO: Fix the code below after deviceStorage was removed
702 MACAddress macAddress = null;
703 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800704 IDeviceObject nextHopDevice =
705 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
706
707 if(nextHopDevice == null){
708 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
709 //Put in the pending paths list first
710 pathsWaitingOnArp.put(peer.getIpAddress(), path);
711 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
712 continue;
713 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700714
pingping-linba5c52f2014-02-11 16:52:01 -0800715 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700716 */
pingping-linba5c52f2014-02-11 16:52:01 -0800717
Jonathan Hartabad6a52013-09-30 18:17:21 +1300718 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200719 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
720 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200721 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200722 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
723 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700724 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700725
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200726 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300727 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700728 }
729 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700730
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200731 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200732 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700733
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200734 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
735 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800736
737 FlowPath flowPath = new FlowPath();
738
739 flowPath.setInstallerId(new CallerId("SDNIP"));
740
741 // Set flowPath FlowPathType and FlowPathUserState
742 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
743 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
744
745 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
746 FlowPathFlags flowPathFlags = new FlowPathFlags();
747 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
748 flowPath.setFlowPathFlags(flowPathFlags);
749
750 // Create the DataPath object: dstSwitchPort
751 SwitchPort dstPort = new SwitchPort();
752 dstPort.setDpid(new Dpid(dstInterface.getDpid()));
753 dstPort.setPort(new Port(dstInterface.getPort()));
754
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200755 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800756
Jonathan Hart45107222013-10-22 17:35:04 -0700757 if (dstInterface.equals(srcInterface)){
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200758 continue;
759 }
pingping-linba5c52f2014-02-11 16:52:01 -0800760
761 // Create flowPath FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800762 flowPath.setFlowId(new FlowId());
763
764 // Create the DataPath object: srcSwitchPort
765 SwitchPort srcPort = new SwitchPort();
766 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
767 srcPort.setPort(new Port(srcInterface.getPort()));
768
769 DataPath dataPath = new DataPath();
770 dataPath.setSrcPort(srcPort);
771 dataPath.setDstPort(dstPort);
772 flowPath.setDataPath(dataPath);
773
774 // Create the Flow Path Match condition(s)
775 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
776 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
777 flowEntryMatch.enableDstMac(dstMacAddress);
778 flowPath.setFlowEntryMatch(flowEntryMatch);
779
780 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
781 // Shortest Path Flow, and is always the last action for the Flow Entries
782 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700783 // TODO: Add the flow by using the new Path Intent framework
784 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800785 if (flowManagerService.addFlow(flowPath) == null) {
786 log.error("Failed to set up MAC based forwarding path to {}, {}",
787 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200788 }
789 else {
pingping-linba5c52f2014-02-11 16:52:01 -0800790 log.debug("Successfully set up MAC based forwarding path to {}, {}",
791 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200792 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700793 */
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200794 }
795 }
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200796
pingping-linba5c52f2014-02-11 16:52:01 -0800797 /**
798 * Pre-actively install all BGP traffic paths from BGP host attachment point
799 * in SDN network to all the virtual gateways to BGP peers in other networks
800 */
801 private void setupBgpPaths(){
802
803 for (BgpPeer bgpPeer : bgpPeers.values()){
804
805 FlowPath flowPath = new FlowPath();
806 flowPath.setInstallerId(new CallerId("SDNIP"));
807
808 // Set flowPath FlowPathType and FlowPathUserState
809 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
810 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
811
812 // Install flow paths between BGPd and its peers
813 // There is no need to set the FlowPathFlags
814 flowPath.setFlowPathFlags(new FlowPathFlags(0));
815
816 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
817
pingping-linba5c52f2014-02-11 16:52:01 -0800818 // Create the Flow Path Match condition(s)
819 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
820 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
821
822 // Match both source address and dest address
823 IPv4Net dstIPv4Net= new IPv4Net(bgpPeer.getIpAddress().getHostAddress()+"/32");
824 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
825
826 IPv4Net srcIPv4Net= new IPv4Net(peerInterface.getIpAddress().getHostAddress()+"/32");
827 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
828
829 // Match TCP protocol
830 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
831
832 // Match destination TCP port
833 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
834 flowPath.setFlowEntryMatch(flowEntryMatch);
835
836 /**
837 * Create the DataPath: BGP -> BGP peer
838 */
839 // Flow path for src-TCP-port
840 DataPath dataPath = new DataPath();
841
842 SwitchPort srcPort = new SwitchPort();
843 srcPort.setDpid(bgpdAttachmentPoint.dpid());
844 srcPort.setPort(bgpdAttachmentPoint.port());
845 dataPath.setSrcPort(srcPort);
846
847 SwitchPort dstPort = new SwitchPort();
848 dstPort.setDpid(new Dpid(peerInterface.getDpid()));
849 dstPort.setPort(new Port(peerInterface.getSwitchPort().port()));
850 dataPath.setDstPort(dstPort);
851
852 flowPath.setDataPath(dataPath);
853
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700854 // TODO: Add the flow by using the new Path Intent framework
855 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800856 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 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700864 */
pingping-linba5c52f2014-02-11 16:52:01 -0800865
866 // Disable dst-TCP-port, and set src-TCP-port
867 flowEntryMatch.disableDstTcpUdpPort();
868 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
869 flowPath.setFlowEntryMatch(flowEntryMatch);
870
871 // Create a new FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800872 flowPath.setFlowId(new FlowId());
873
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700874 // TODO: Add the flow by using the new Path Intent framework
875 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800876 if (flowManagerService.addFlow(flowPath) == null) {
877 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
878 bgpPeer.getIpAddress().getHostAddress());
879 }
880 else {
881 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
882 bgpPeer.getIpAddress().getHostAddress());
883 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700884 */
pingping-linba5c52f2014-02-11 16:52:01 -0800885
886 /**
887 * Create the DataPath: BGP <-BGP peer
888 */
889 // Reversed BGP flow path for src-TCP-port
pingping-linba5c52f2014-02-11 16:52:01 -0800890 flowPath.setFlowId(new FlowId());
891
892 DataPath reverse_dataPath = new DataPath();
893
894 SwitchPort reverse_dstPort = new SwitchPort();
895 reverse_dstPort.setDpid(bgpdAttachmentPoint.dpid());
896 reverse_dstPort.setPort(bgpdAttachmentPoint.port());
897 reverse_dataPath.setDstPort(reverse_dstPort);
898
899 SwitchPort reverse_srcPort = new SwitchPort();
900 reverse_srcPort.setDpid(new Dpid(peerInterface.getDpid()));
901 reverse_srcPort.setPort(new Port(peerInterface.getSwitchPort().port()));
902 reverse_dataPath.setSrcPort(reverse_srcPort);
903 flowPath.setDataPath(reverse_dataPath);
904
905 // reverse the dst IP and src IP addresses
906 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
907 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
908 flowPath.setFlowEntryMatch(flowEntryMatch);
909
910 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
911
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700912 // TODO: Add the flow by using the new Path Intent framework
913 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800914 if (flowManagerService.addFlow(flowPath) == null) {
915
916 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
917 bgpPeer.getIpAddress().getHostAddress());
918 }
919 else {
920 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
921 bgpPeer.getIpAddress().getHostAddress());
922 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700923 */
pingping-linba5c52f2014-02-11 16:52:01 -0800924
925 // Reversed BGP flow path for dst-TCP-port
pingping-linba5c52f2014-02-11 16:52:01 -0800926 flowPath.setFlowId(new FlowId());
927
928 // Disable src-TCP-port, and set the dst-TCP-port
929 flowEntryMatch.disableSrcTcpUdpPort();
930 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
931 flowPath.setFlowEntryMatch(flowEntryMatch);
932
933 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700934
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700935 // TODO: Add the flow by using the new Path Intent framework
936 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800937 if (flowManagerService.addFlow(flowPath) == null) {
938 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
939 bgpPeer.getIpAddress().getHostAddress());
940 }
941 else {
942 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
943 bgpPeer.getIpAddress().getHostAddress());
944 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700945 */
pingping-linba5c52f2014-02-11 16:52:01 -0800946
947 /**
948 * ICMP paths between BGPd and its peers
949 */
950 //match ICMP protocol BGP <- Peer
pingping-linba5c52f2014-02-11 16:52:01 -0800951 flowPath.setFlowId(new FlowId());
952
953 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
954 flowEntryMatch.disableSrcTcpUdpPort();
955 flowEntryMatch.disableDstTcpUdpPort();
956
957 flowPath.setFlowEntryMatch(flowEntryMatch);
958
959 flowPath.setDataPath(reverse_dataPath);
960
961 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
962
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700963 // TODO: Add the flow by using the new Path Intent framework
964 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800965 if (flowManagerService.addFlow(flowPath) == null) {
966
967 log.error("Failed to set up ICMP path BGP <- Peer {}",
968 bgpPeer.getIpAddress().getHostAddress());
969 }
970 else {
971 log.debug("Successfully set up ICMP path BGP <- Peer {}",
972 bgpPeer.getIpAddress().getHostAddress());
973 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700974 */
pingping-linba5c52f2014-02-11 16:52:01 -0800975
976 //match ICMP protocol BGP -> Peer
pingping-linba5c52f2014-02-11 16:52:01 -0800977 flowPath.setFlowId(new FlowId());
978
979 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
980 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
981 flowPath.setFlowEntryMatch(flowEntryMatch);
982
983 flowPath.setDataPath(dataPath);
984
985 log.debug("ICMP flowPath: {}", flowPath.toString());
986
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700987 // TODO: Add the flow by using the new Path Intent framework
988 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800989 if (flowManagerService.addFlow(flowPath) == null) {
990
991 log.error("Failed to set up ICMP path BGP -> Peer {}",
992 bgpPeer.getIpAddress().getHostAddress());
993 }
994 else {
995 log.debug("Successfully set up ICMP path BGP -> Peer {}",
996 bgpPeer.getIpAddress().getHostAddress());
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200997 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700998 */
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200999 }
1000 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001001
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001002 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +13001003 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001004 log.debug("Received ARP response: {} => {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +13001005 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001006
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001007 /*
1008 * We synchronize on this to prevent changes to the ptree while we're pushing
1009 * flows to the switches. If the ptree changes, the ptree and switches
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001010 * could get out of sync.
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001011 */
1012 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001013 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001014
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001015 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001016 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001017 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001018 path.getDstInterface().getSwitchPort()});
1019 //These paths should always be to BGP peers. Paths to non-peers are
1020 //handled once the first prefix is ready to push
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001021 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001022 //A path already got pushed to this endpoint while we were waiting
1023 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001024 if (path.isPermanent()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001025 pushedPaths.get(path.getDstIpAddress()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +12001026 }
1027 }
1028 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001029 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001030 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +12001031 }
1032 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001033
Jonathan Hart309889c2013-08-13 23:26:24 +12001034 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001035
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001036 for (RibUpdate update : prefixesToPush) {
1037 //These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001038
1039 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001040 if (rib != null && rib.equals(update.getRibEntry())) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001041 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001042 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001043 //We only push prefix flows if the prefix is still in the ptree
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001044 //and the next hop is the same as our update. The prefix could
1045 //have been removed while we were waiting for the ARP, or the
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001046 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +12001047 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001048 } else {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001049 log.debug("Received ARP response, but {},{} is no longer in ptree",
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001050 update.getPrefix(), update.getRibEntry());
1051 }
1052 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001053 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001054 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001055
pingping-linba5c52f2014-02-11 16:52:01 -08001056 //TODO wait the priority module of the flow Manager
Jonathan Hartc82051c2013-08-24 15:12:20 +12001057 private void setupArpFlows() {
1058 OFMatch match = new OFMatch();
1059 match.setDataLayerType(Ethernet.TYPE_ARP);
1060 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001061
Jonathan Hartc82051c2013-08-24 15:12:20 +12001062 OFFlowMod fm = new OFFlowMod();
1063 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001064
Jonathan Hartc82051c2013-08-24 15:12:20 +12001065 OFActionOutput action = new OFActionOutput();
1066 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1067 action.setMaxLength((short)0xffff);
1068 List<OFAction> actions = new ArrayList<OFAction>(1);
1069 actions.add(action);
1070 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001071
Jonathan Hartc82051c2013-08-24 15:12:20 +12001072 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001073 .setHardTimeout((short)0)
1074 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1075 .setCookie(0)
1076 .setCommand(OFFlowMod.OFPFC_ADD)
1077 .setPriority(ARP_PRIORITY)
Jonathan Hartc82051c2013-08-24 15:12:20 +12001078 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001079
Jonathan Hartc82051c2013-08-24 15:12:20 +12001080 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001081 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +12001082 }
1083 }
pingping-linba5c52f2014-02-11 16:52:01 -08001084 //TODO need update, waiting for the priority feature from flow Manager
Jonathan Hartf886fa12013-09-18 14:46:29 +12001085 private void setupDefaultDropFlows() {
1086 OFFlowMod fm = new OFFlowMod();
1087 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001088 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001089
Jonathan Hartf886fa12013-09-18 14:46:29 +12001090 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001091 .setHardTimeout((short)0)
1092 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1093 .setCookie(0)
1094 .setCommand(OFFlowMod.OFPFC_ADD)
1095 .setPriority((short)0)
Jonathan Hartf886fa12013-09-18 14:46:29 +12001096 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001097
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001098 OFFlowMod fmLLDP;
1099 OFFlowMod fmBDDP;
1100 try {
pingping-linba5c52f2014-02-11 16:52:01 -08001101 fmLLDP = fm.clone();
1102 fmBDDP = fm.clone();
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001103 } catch (CloneNotSupportedException e1) {
1104 log.error("Error cloning flow mod", e1);
1105 return;
1106 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001107
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001108 OFMatch matchLLDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001109 matchLLDP.setDataLayerType((short)0x88cc);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001110 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1111 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001112
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001113 OFMatch matchBDDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001114 matchBDDP.setDataLayerType((short)0x8942);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001115 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1116 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001117
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001118 OFActionOutput action = new OFActionOutput();
1119 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1120 action.setMaxLength((short)0xffff);
1121 List<OFAction> actions = new ArrayList<OFAction>(1);
1122 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001123
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001124 fmLLDP.setActions(actions);
1125 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001126
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001127 fmLLDP.setPriority(ARP_PRIORITY);
1128 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1129 fmBDDP.setPriority(ARP_PRIORITY);
1130 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001131
1132 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
Jonathan Hart1912afc2013-10-11 12:02:44 +13001133 flowModList.add(fm);
1134 flowModList.add(fmLLDP);
1135 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001136
Jonathan Hartf886fa12013-09-18 14:46:29 +12001137 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001138 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001139 }
1140 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001141
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001142 private void beginRouting(){
1143 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov1237e392014-03-20 16:24:06 -07001144 // TODO: Fix for the new Topology Network Graph
1145 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001146
pingping-linba5c52f2014-02-11 16:52:01 -08001147 // Wait Pavlin's API. We need the following functions.
1148 /*setupArpFlows();
1149 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001150
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001151 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001152 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001153
Jonathan Harte7694532013-09-12 12:34:46 +12001154 //Suppress link discovery on external-facing router ports
1155 for (Interface intf : interfaces.values()) {
1156 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1157 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001158
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001159 bgpUpdatesExecutor.execute(new Runnable() {
1160 @Override
1161 public void run() {
1162 doUpdatesThread();
1163 }
1164 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001165 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001166
pingping-linba5c52f2014-02-11 16:52:01 -08001167 // Before inserting the paths for BGP traffic, we should check
1168 // whether all the switches in the configure file are discovered by onos.
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001169 private void checkSwitchesConnected(){
1170 for (String dpid : switches){
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -07001171 // TODO: Fix the code below after topoSwitchSerice was removed
1172 /*
pingping-linba5c52f2014-02-11 16:52:01 -08001173 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1174 getActiveSwitches().iterator();
1175 while(activeSwitches.hasNext())
1176 {
1177 ISwitchObject switchObject = activeSwitches.next();
1178 if (switchObject.getDPID().equals(dpid)) {
1179 break;
1180 }
1181 if(activeSwitches.hasNext() == false) {
1182 log.debug("Not all switches are here yet");
1183 return;
1184 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001185 }
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -07001186 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001187 }
1188 switchesConnected = true;
1189 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001190
Jonathan Hartc824ad02013-07-03 15:58:45 +12001191 //Actually we only need to go half way round to verify full mesh connectivity
1192 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001193 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001194 for (Interface dstInterface : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001195 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -07001196 if (dstInterface.equals(srcInterface)) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001197 continue;
1198 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001199
Pavlin Radoslavov1237e392014-03-20 16:24:06 -07001200 // TODO: Fix for the new Topology Network Graph
1201 /*
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001202 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001203 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001204
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001205 if (shortestPath == null){
1206 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001207 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001208 return;
1209 }
Pavlin Radoslavov1237e392014-03-20 16:24:06 -07001210 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001211 }
1212 }
1213 topologyReady = true;
1214 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001215
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001216 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001217 if (!switchesConnected){
1218 checkSwitchesConnected();
1219 }
1220 boolean oldTopologyReadyStatus = topologyReady;
1221 if (switchesConnected && !topologyReady){
1222 checkTopologyReady();
1223 }
1224 if (!oldTopologyReadyStatus && topologyReady){
1225 beginRouting();
1226 }
1227 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001228
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001229 private void doUpdatesThread() {
1230 boolean interrupted = false;
1231 try {
1232 while (true) {
1233 try {
1234 RibUpdate update = ribUpdates.take();
1235 switch (update.getOperation()){
1236 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001237 if (validateUpdate(update)) {
1238 processRibAdd(update);
1239 }
1240 else {
1241 log.debug("Rib UPDATE out of order: {} via {}",
1242 update.getPrefix(), update.getRibEntry().getNextHop());
1243 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001244 break;
1245 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001246 if (validateUpdate(update)) {
1247 processRibDelete(update);
1248 }
1249 else {
1250 log.debug("Rib DELETE out of order: {} via {}",
1251 update.getPrefix(), update.getRibEntry().getNextHop());
1252 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001253 break;
1254 }
1255 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001256 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001257 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001258 } catch (Exception e) {
1259 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001260 }
1261 }
1262 } finally {
1263 if (interrupted) {
1264 Thread.currentThread().interrupt();
1265 }
1266 }
1267 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001268
Jonathan Harte4c98692013-10-18 17:40:03 -07001269 private boolean validateUpdate(RibUpdate update) {
1270 RibEntry newEntry = update.getRibEntry();
1271 RibEntry oldEntry = ptree.lookup(update.getPrefix());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001272
Jonathan Harte4c98692013-10-18 17:40:03 -07001273 //If there is no existing entry we must assume this is the most recent
1274 //update. However this might not always be the case as we might have a
1275 //POST then DELETE reordering.
1276 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1277 if (oldEntry == null) {
1278 return true;
1279 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001280
Jonathan Harte4c98692013-10-18 17:40:03 -07001281 // This handles the case where routes are gathered in the initial
1282 // request because they don't have sequence number info
1283 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1284 return true;
1285 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001286
Jonathan Harte4c98692013-10-18 17:40:03 -07001287 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1288 return true;
1289 }
1290 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1291 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1292 return true;
1293 }
1294 else {
1295 return false;
1296 }
1297 }
1298 else {
1299 return false;
1300 }
1301 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001302
1303 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001304 public void topologyChanged() {
1305 if (topologyReady) {
1306 return;
1307 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001308
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001309 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001310 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001311 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1312 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001313 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001314 refreshNeeded = true;
1315 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001316
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001317 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001318
Jonathan Hart98957bf2013-07-01 14:49:24 +12001319 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1320 synchronized (linkUpdates) {
1321 linkUpdates.add(ldu);
1322 }
1323 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001324 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001325
Jonathan Hart64c0b202013-08-20 15:45:07 +12001326 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001327 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001328 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001329 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001330
1331 @Override
1332 public void addedSwitch(IOFSwitch sw) {
1333 if (!topologyReady) {
1334 sw.clearAllFlowMods();
1335 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001336
Jonathan Hart1912afc2013-10-11 12:02:44 +13001337 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001338 }
1339
1340 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001341 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001342
1343 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001344 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001345
1346 @Override
1347 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001348 return "BgpRoute";
1349 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001350
Jonathan Hart08ee8522013-09-22 17:34:43 +12001351 /*
Jonathan Harta8887642013-10-28 13:46:54 -07001352 * IConfigInfoService methods
Jonathan Hart08ee8522013-09-22 17:34:43 +12001353 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001354
Jonathan Hart08ee8522013-09-22 17:34:43 +12001355 @Override
1356 public boolean isInterfaceAddress(InetAddress address) {
1357 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1358 return (intf != null && intf.getIpAddress().equals(address));
1359 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001360
Jonathan Hart08ee8522013-09-22 17:34:43 +12001361 @Override
1362 public boolean inConnectedNetwork(InetAddress address) {
1363 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1364 return (intf != null && !intf.getIpAddress().equals(address));
1365 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001366
Jonathan Hart08ee8522013-09-22 17:34:43 +12001367 @Override
1368 public boolean fromExternalNetwork(long inDpid, short inPort) {
1369 for (Interface intf : interfaces.values()) {
1370 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1371 return true;
1372 }
1373 }
1374 return false;
1375 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001376
Jonathan Hart08ee8522013-09-22 17:34:43 +12001377 @Override
1378 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1379 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1380 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001381
Jonathan Hart08ee8522013-09-22 17:34:43 +12001382 @Override
1383 public boolean hasLayer3Configuration() {
1384 return !interfaces.isEmpty();
1385 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001386
Jonathan Hart08ee8522013-09-22 17:34:43 +12001387 @Override
1388 public MACAddress getRouterMacAddress() {
1389 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001390 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001391
Jonathan Harta8887642013-10-28 13:46:54 -07001392 @Override
1393 public short getVlan() {
1394 return vlan;
1395 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001396}