blob: 501dbf0b2789a6352e30b2de6a07b7a4fc16e8cc [file] [log] [blame]
HIGUCHI Yutaea60e5f2013-06-12 11:10:21 -07001package net.onrc.onos.ofcontroller.bgproute;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
Jonathan Hartd1f23252013-06-13 15:17:05 +12003import java.io.File;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07004import java.io.IOException;
5import java.net.InetAddress;
pingping-lina2cbfad2013-03-07 08:39:21 +08006import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07007import java.util.Collection;
pingping-lina2cbfad2013-03-07 08:39:21 +08008import java.util.HashMap;
Jonathan Hart98957bf2013-07-01 14:49:24 +12009import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070010import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070011import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120012import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120013import java.util.concurrent.BlockingQueue;
14import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120015import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120016import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080019
Jonathan Hart61ba9372013-05-19 20:10:29 -070020import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070021import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart64c0b202013-08-20 15:45:07 +120022import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120027import net.floodlightcontroller.core.util.SingletonTask;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070028import net.floodlightcontroller.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120029import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080030import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120031import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080032import net.floodlightcontroller.topology.ITopologyListener;
33import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120034import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120035import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
pingping-linba5c52f2014-02-11 16:52:01 -080036import net.onrc.onos.ofcontroller.core.IDeviceStorage;
37import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
38import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
Jonathan Hart98957bf2013-07-01 14:49:24 +120039import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
pingping-linba5c52f2014-02-11 16:52:01 -080040import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoSwitchService;
Jonathan Hartebba1e12013-10-29 11:37:02 -070041import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
pingping-linba5c52f2014-02-11 16:52:01 -080042import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
Jonathan Hart98957bf2013-07-01 14:49:24 +120043import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
pingping-linba5c52f2014-02-11 16:52:01 -080044import net.onrc.onos.ofcontroller.core.internal.TopoSwitchServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070045import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
46import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harte7694532013-09-12 12:34:46 +120047import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120048import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
pingping-linba5c52f2014-02-11 16:52:01 -080049import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
pingping-linba5c52f2014-02-11 16:52:01 -080050import net.onrc.onos.ofcontroller.util.CallerId;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070051import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120052import net.onrc.onos.ofcontroller.util.Dpid;
pingping-linba5c52f2014-02-11 16:52:01 -080053import net.onrc.onos.ofcontroller.util.FlowEntryAction;
54import net.onrc.onos.ofcontroller.util.FlowEntryActions;
55import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
56import net.onrc.onos.ofcontroller.util.FlowId;
57import net.onrc.onos.ofcontroller.util.FlowPath;
58import net.onrc.onos.ofcontroller.util.FlowPathFlags;
59import net.onrc.onos.ofcontroller.util.FlowPathType;
60import net.onrc.onos.ofcontroller.util.FlowPathUserState;
61import net.onrc.onos.ofcontroller.util.IPv4Net;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070062import net.onrc.onos.ofcontroller.util.Port;
63import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080064import net.sf.json.JSONArray;
65import net.sf.json.JSONObject;
66import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080067
Jonathan Hartd1f23252013-06-13 15:17:05 +120068import org.codehaus.jackson.JsonParseException;
69import org.codehaus.jackson.map.JsonMappingException;
70import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070071import org.openflow.protocol.OFFlowMod;
72import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070073import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120074import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070075import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070076import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120077import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080078import org.slf4j.Logger;
79import org.slf4j.LoggerFactory;
80
Jonathan Hart4dfc3652013-08-02 20:22:36 +120081import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120082import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120083import com.google.common.collect.Multimaps;
84import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120085import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120086import com.google.common.util.concurrent.ThreadFactoryBuilder;
87
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070088public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120089 ITopologyListener, IArpRequester,
Jonathan Hart7804bea2014-01-07 10:50:52 -080090 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070091
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070092 private final static Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080093
Jonathan Hartf247ee72013-10-18 18:57:28 -070094 private IFloodlightProviderService floodlightProvider;
Jonathan Hart3a326122013-10-21 11:51:13 -070095 private ITopologyService topologyService;
Jonathan Hartf247ee72013-10-18 18:57:28 -070096 private ILinkDiscoveryService linkDiscoveryService;
97 private IRestApiService restApi;
pingping-linba5c52f2014-02-11 16:52:01 -080098 private IProxyArpService proxyArp;
pingping-linba5c52f2014-02-11 16:52:01 -080099 private IDeviceStorage deviceStorage;
100 private ITopoSwitchService topoSwitchService;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700101
Jonathan Hartf247ee72013-10-18 18:57:28 -0700102 private IPatriciaTrie<RibEntry> ptree;
103 private IPatriciaTrie<Interface> interfacePtrie;
104 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700105
Jonathan Hartf247ee72013-10-18 18:57:28 -0700106 private String bgpdRestIp;
107 private String routerId;
108 private String configFilename = "config.json";
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700109
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700110 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
111 //the controller/OS should hand out cookie IDs to prevent conflicts.
Jonathan Hartf247ee72013-10-18 18:57:28 -0700112 private final long APP_COOKIE = 0xa0000000000000L;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700113 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Jonathan Hartf247ee72013-10-18 18:57:28 -0700114 private final long L2_FWD_COOKIE = APP_COOKIE + 1;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700115 //Cookie for flows in ingress switches that rewrite the MAC address
Jonathan Hartf247ee72013-10-18 18:57:28 -0700116 private final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200117 //Cookie for flows that setup BGP paths
Jonathan Hartf247ee72013-10-18 18:57:28 -0700118 private final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200119 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
120 //need to be higher priority than this otherwise the rewrite may not get done
Jonathan Hartf247ee72013-10-18 18:57:28 -0700121 private final short SDNIP_PRIORITY = 10;
122 private final short ARP_PRIORITY = 20;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700123
Jonathan Hartf247ee72013-10-18 18:57:28 -0700124 private final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700125
Jonathan Hartf247ee72013-10-18 18:57:28 -0700126 private final int TOPO_DETECTION_WAIT = 2; //seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700127
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200128 //Configuration stuff
Jonathan Hartf247ee72013-10-18 18:57:28 -0700129 private List<String> switches;
130 private Map<String, Interface> interfaces;
131 private Map<InetAddress, BgpPeer> bgpPeers;
132 private SwitchPort bgpdAttachmentPoint;
133 private MACAddress bgpdMacAddress;
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700134 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700135
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200136 //True when all switches have connected
Jonathan Hartf247ee72013-10-18 18:57:28 -0700137 private volatile boolean switchesConnected = false;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200138 //True when we have a full mesh of shortest paths between gateways
Jonathan Hartf247ee72013-10-18 18:57:28 -0700139 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200140
Jonathan Hartf247ee72013-10-18 18:57:28 -0700141 private ArrayList<LDUpdate> linkUpdates;
142 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700143
Jonathan Hartf247ee72013-10-18 18:57:28 -0700144 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700145
Jonathan Hartf247ee72013-10-18 18:57:28 -0700146 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700147
Jonathan Hartf247ee72013-10-18 18:57:28 -0700148 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700149
Jonathan Hartf247ee72013-10-18 18:57:28 -0700150 private Map<InetAddress, Path> pushedPaths;
151 private Map<Prefix, Path> prefixToPath;
pingping-linba5c52f2014-02-11 16:52:01 -0800152// private Multimap<Prefix, PushedFlowMod> pushedFlows;
153 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700154
Jonathan Hart1912afc2013-10-11 12:02:44 +1300155 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700156
Pavlin Radoslavov1237e392014-03-20 16:24:06 -0700157 // TODO: Fix for the new Topology Network Graph
158 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700159
Jonathan Hartf247ee72013-10-18 18:57:28 -0700160 private class TopologyChangeDetector implements Runnable {
Jonathan Hart98957bf2013-07-01 14:49:24 +1200161 @Override
162 public void run() {
163 log.debug("Running topology change detection task");
164 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200165 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200166 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700167
Jonathan Hart98957bf2013-07-01 14:49:24 +1200168 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700169
Jonathan Hart98957bf2013-07-01 14:49:24 +1200170 Iterator<LDUpdate> it = linkUpdates.iterator();
171 while (it.hasNext()){
172 LDUpdate ldu = it.next();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700173 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
Jonathan Hart98957bf2013-07-01 14:49:24 +1200174 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700175
Jonathan Hart98957bf2013-07-01 14:49:24 +1200176 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200177 it.remove();
178 }
179 }
180 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700181
Jonathan Hart64c0b202013-08-20 15:45:07 +1200182 if (!topologyReady) {
183 if (linkUpdates.isEmpty()){
184 //All updates have been seen in network map.
185 //We can check if topology is ready
186 log.debug("No known changes outstanding. Checking topology now");
187 checkStatus();
188 }
189 else {
190 //We know of some link updates that haven't propagated to the database yet
191 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
192 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
193 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200194 }
195 }
196 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700197
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700198 private void readConfiguration(String configFilename){
199 File gatewaysFile = new File(configFilename);
Jonathan Hartd1f23252013-06-13 15:17:05 +1200200 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700201
Jonathan Hartd1f23252013-06-13 15:17:05 +1200202 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200203 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700204
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200205 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200206 interfaces = new HashMap<String, Interface>();
207 for (Interface intf : config.getInterfaces()){
208 interfaces.put(intf.getName(), intf);
209 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200210 bgpPeers = new HashMap<InetAddress, BgpPeer>();
211 for (BgpPeer peer : config.getPeers()){
212 bgpPeers.put(peer.getIpAddress(), peer);
213 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700214
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200215 bgpdAttachmentPoint = new SwitchPort(
216 new Dpid(config.getBgpdAttachmentDpid()),
217 new Port(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700218
Jonathan Hart2f790d22013-08-15 14:01:24 +1200219 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700220 vlan = config.getVlan();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200221 } catch (JsonParseException e) {
222 log.error("Error in JSON file", e);
223 System.exit(1);
224 } catch (JsonMappingException e) {
225 log.error("Error in JSON file", e);
226 System.exit(1);
227 } catch (IOException e) {
228 log.error("Error reading JSON file", e);
229 System.exit(1);
230 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700231
Jonathan Hartabf10222013-08-13 10:19:34 +1200232 //Populate the interface Patricia Trie
233 for (Interface intf : interfaces.values()) {
234 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
235 interfacePtrie.put(prefix, intf);
236 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700237 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700238
pingping-lina2cbfad2013-03-07 08:39:21 +0800239 @Override
240 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700241 Collection<Class<? extends IFloodlightService>> l
Jonathan Hart61ba9372013-05-19 20:10:29 -0700242 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800243 l.add(IBgpRouteService.class);
Jonathan Harta8887642013-10-28 13:46:54 -0700244 l.add(IConfigInfoService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800245 return l;
246 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700247
pingping-lina2cbfad2013-03-07 08:39:21 +0800248 @Override
249 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700250 Map<Class<? extends IFloodlightService>, IFloodlightService> m
Jonathan Hart61ba9372013-05-19 20:10:29 -0700251 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800252 m.put(IBgpRouteService.class, this);
Jonathan Harta8887642013-10-28 13:46:54 -0700253 m.put(IConfigInfoService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800254 return m;
255 }
256
pingping-lina2cbfad2013-03-07 08:39:21 +0800257 @Override
258 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700259 Collection<Class<? extends IFloodlightService>> l
Jonathan Hart61ba9372013-05-19 20:10:29 -0700260 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800261 l.add(IFloodlightProviderService.class);
262 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700263 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800264 return l;
265 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700266
pingping-lina2cbfad2013-03-07 08:39:21 +0800267 @Override
268 public void init(FloodlightModuleContext context)
269 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700270
Jonathan Hart29b972d2013-08-12 23:43:51 +1200271 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200272 interfacePtrie = new PatriciaTrie<Interface>(32);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700273
pingping-linba5c52f2014-02-11 16:52:01 -0800274 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700275
pingping-lina2cbfad2013-03-07 08:39:21 +0800276 // Register floodlight provider and REST handler.
277 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700278 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200279 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200280 restApi = context.getServiceImpl(IRestApiService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800281 proxyArp = context.getServiceImpl(IProxyArpService.class);
282
283 deviceStorage = new DeviceStorageImpl();
284 deviceStorage.init("", "");
285
Jonathan Hart98957bf2013-07-01 14:49:24 +1200286 linkUpdates = new ArrayList<LDUpdate>();
287 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
288 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700289
pingping-linba5c52f2014-02-11 16:52:01 -0800290 topoSwitchService = new TopoSwitchServiceImpl();
291
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200292 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200293 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
294 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700295
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200296 pushedPaths = new HashMap<InetAddress, Path>();
297 prefixToPath = new HashMap<Prefix, Path>();
pingping-linba5c52f2014-02-11 16:52:01 -0800298// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
299 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700300
Jonathan Hart1912afc2013-10-11 12:02:44 +1300301 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700302
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200303 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
304 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700305
Jonathan Hart61ba9372013-05-19 20:10:29 -0700306 //Read in config values
307 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
308 if (bgpdRestIp == null){
309 log.error("BgpdRestIp property not found in config file");
310 System.exit(1);
311 }
312 else {
313 log.info("BgpdRestIp set to {}", bgpdRestIp);
314 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700315
Jonathan Hart61ba9372013-05-19 20:10:29 -0700316 routerId = context.getConfigParams(this).get("RouterId");
317 if (routerId == null){
318 log.error("RouterId property not found in config file");
319 System.exit(1);
320 }
321 else {
322 log.info("RouterId set to {}", routerId);
323 }
pingping-linba5c52f2014-02-11 16:52:01 -0800324
Jonathan Hart9575cb62013-07-05 13:43:49 +1200325 String configFilenameParameter = context.getConfigParams(this).get("configfile");
326 if (configFilenameParameter != null){
327 configFilename = configFilenameParameter;
328 }
329 log.debug("Config file set to {}", configFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700330
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700331 readConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200332 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700333
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200334 @Override
335 public void startUp(FloodlightModuleContext context) {
336 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700337 topologyService.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200338 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800339
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200340 //Retrieve the RIB from BGPd during startup
341 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800342 }
343
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700344 @Override
Jonathan Hart29b972d2013-08-12 23:43:51 +1200345 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800346 return ptree;
347 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700348
349 @Override
Jonathan Hart61ba9372013-05-19 20:10:29 -0700350 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200351 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800352 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700353
354 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800355 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700356 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800357 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700358
359 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800360 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700361 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800362 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700363
Jonathan Hart61ba9372013-05-19 20:10:29 -0700364 private void retrieveRib(){
365 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
366 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700367
Jonathan Hart61ba9372013-05-19 20:10:29 -0700368 if (response.equals("")){
369 return;
370 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700371
Jonathan Hart61ba9372013-05-19 20:10:29 -0700372 response = response.replaceAll("\"", "'");
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700373 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700374 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
375 String router_id = jsonObj.getString("router-id");
376
377 int size = rib_json_array.size();
378
379 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700380
Jonathan Hart61ba9372013-05-19 20:10:29 -0700381 for (int j = 0; j < size; j++) {
382 JSONObject second_json_object = rib_json_array.getJSONObject(j);
383 String prefix = second_json_object.getString("prefix");
384 String nexthop = second_json_object.getString("nexthop");
385
386 //insert each rib entry into the local rib;
387 String[] substring = prefix.split("/");
388 String prefix1 = substring[0];
389 String mask1 = substring[1];
390
391 Prefix p;
392 try {
393 p = new Prefix(prefix1, Integer.valueOf(mask1));
394 } catch (NumberFormatException e) {
395 log.warn("Wrong mask format in RIB JSON: {}", mask1);
396 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200397 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700398 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
399 continue;
400 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700401
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200402 RibEntry rib = new RibEntry(router_id, nexthop);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700403
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200404 try {
405 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
406 } catch (InterruptedException e) {
407 log.debug("Interrupted while pushing onto update queue");
408 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700409 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700410 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700411
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200412 @Override
413 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200414 try {
415 ribUpdates.put(update);
416 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200417 log.debug("Interrupted while putting on ribUpdates queue", e);
418 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200419 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200420 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700421
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200422 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200423 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700424
Jonathan Hart9ea31212013-08-12 21:40:34 +1200425 log.debug("Processing prefix add {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700426
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200427 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700428
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200429 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200430 //There was an existing nexthop for this prefix. This update supersedes that,
431 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200432 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200433 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700434
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200435 if (update.getRibEntry().getNextHop().equals(
436 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200437 //Route originated by SDN domain
438 //We don't handle these at the moment
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700439 log.debug("Own route {} to {}", prefix,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200440 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200441 return;
442 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700443
Jonathan Hart309889c2013-08-13 23:26:24 +1200444 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200445 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700446
Jonathan Hart309889c2013-08-13 23:26:24 +1200447 private void _processRibAdd(RibUpdate update) {
448 Prefix prefix = update.getPrefix();
449 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700450
Jonathan Hart309889c2013-08-13 23:26:24 +1200451 InetAddress dstIpAddress = rib.getNextHop();
pingping-linba5c52f2014-02-11 16:52:01 -0800452 MACAddress nextHopMacAddress;
453
454 // See if we know the MAC address of the next hop
455 // TODO if we do not treat the next hop as a device in the future, we need to update this
456 IDeviceObject nextHopDevice =
457 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700458
pingping-linba5c52f2014-02-11 16:52:01 -0800459 if (nextHopDevice == null){
460 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
461 prefixesWaitingOnArp.put(dstIpAddress,
462 new RibUpdate(Operation.UPDATE, prefix, rib));
463 proxyArp.sendArpRequest(dstIpAddress, this, true);
464 return;
465
466 }
467 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700468
pingping-linba5c52f2014-02-11 16:52:01 -0800469 // Find the attachment point (egress interface) of the next hop
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200470 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200471 if (bgpPeers.containsKey(dstIpAddress)) {
472 //Route to a peer
473 log.debug("Route to peer {}", dstIpAddress);
474 BgpPeer peer = bgpPeers.get(dstIpAddress);
475 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200476 }
477 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200478 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200479 log.debug("Route to non-peer {}", dstIpAddress);
480 egressInterface = interfacePtrie.match(
481 new Prefix(dstIpAddress.getAddress(), 32));
482 if (egressInterface == null) {
483 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
484 return;
485 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200486 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700487
Jonathan Hart309889c2013-08-13 23:26:24 +1200488 if (nextHopMacAddress == null) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700489 prefixesWaitingOnArp.put(dstIpAddress,
Jonathan Hart309889c2013-08-13 23:26:24 +1200490 new RibUpdate(Operation.UPDATE, prefix, rib));
491 proxyArp.sendArpRequest(dstIpAddress, this, true);
492 return;
493 }
494 else {
495 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200496 //If the prefix is for a non-peer we need to ensure there's a path,
497 //and push one if there isn't.
498 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200499 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200500 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300501 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200502 pushedPaths.put(dstIpAddress, path);
503 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700504
Jonathan Hart309889c2013-08-13 23:26:24 +1200505 path.incrementUsers();
506 prefixToPath.put(prefix, path);
507 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700508
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200509 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200510 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
511 }
512 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700513
pingping-linba5c52f2014-02-11 16:52:01 -0800514 /**
515 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
516 * to all other border switches
517 */
518 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
519 MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700520 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300521 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700522
pingping-linba5c52f2014-02-11 16:52:01 -0800523 FlowPath flowPath = new FlowPath();
524 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700525
pingping-linba5c52f2014-02-11 16:52:01 -0800526 // Set flowPath FlowPathType and FlowPathUserState
527 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
528 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
529
530 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
531 // only to the first-host switches
532 FlowPathFlags flowPathFlags = new FlowPathFlags();
533 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
534 flowPath.setFlowPathFlags(flowPathFlags);
535
536 // Create the DataPath object: dstSwitchPort
537 SwitchPort dstPort = new SwitchPort();
538 dstPort.setDpid(new Dpid(egressInterface.getDpid()));
539 dstPort.setPort(new Port(egressInterface.getPort()));
540
541 // We only need one flow mod per switch, so pick one interface on each switch
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200542 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
543 for (Interface intf : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700544 if (!srcInterfaces.containsKey(intf.getDpid())
Jonathan Hart45107222013-10-22 17:35:04 -0700545 && !intf.equals(egressInterface)) {
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200546 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200547 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200548 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200549 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800550
551 if (egressInterface.equals(srcInterface)){
552 continue;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200553 }
pingping-linba5c52f2014-02-11 16:52:01 -0800554
555 // Create flowPath FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800556 flowPath.setFlowId(new FlowId());
557
558 // Create DataPath object: srcSwitchPort
559 SwitchPort srcPort = new SwitchPort();
560 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
561 srcPort.setPort(new Port(srcInterface.getPort()));
562
563 DataPath dataPath = new DataPath();
564 dataPath.setSrcPort(srcPort);
565 dataPath.setDstPort(dstPort);
566 flowPath.setDataPath(dataPath);
567
568 // Create flow path matching condition(s): IPv4 Prefix
569 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
570 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
571 IPv4Net dstIPv4Net= new IPv4Net(prefix.toString());
572 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
573 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300574
575 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800576 * Create the Flow Entry Action(s): dst-MAC rewrite action
Jonathan Hart1912afc2013-10-11 12:02:44 +1300577 */
pingping-linba5c52f2014-02-11 16:52:01 -0800578 FlowEntryActions flowEntryActions = new FlowEntryActions();
579 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
580 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
581 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
582 flowEntryActions.addAction(flowEntryAction1);
583 flowPath.setFlowEntryActions(flowEntryActions);
584
585 // Flow Path installation, only to first hop switches
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700586 // TODO: Add the flow by using the new Path Intent framework
587 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800588 if (flowManagerService.addFlow(flowPath) == null) {
589 log.error("Failed to install flow path to the first hop for " +
590 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
591 nextHopMacAddress);
592 }
593 else {
594 log.debug("Successfully installed flow path to the first hop " +
595 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
596 nextHopMacAddress);
597
598 pushedFlowIds.put(prefix, flowPath.flowId());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200599 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700600 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200601 }
602 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700603
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200604 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200605 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700606
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200607 if (ptree.remove(prefix, update.getRibEntry())) {
608 /*
609 * Only delete flows if an entry was actually removed from the trie.
610 * If no entry was removed, the <prefix, nexthop> wasn't there so
611 * it's probably already been removed and we don't need to do anything
612 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200613 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200614 }
615 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700616
Jonathan Hart309889c2013-08-13 23:26:24 +1200617 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
618 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700619
Jonathan Hart309889c2013-08-13 23:26:24 +1200620 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700621
Jonathan Hart309889c2013-08-13 23:26:24 +1200622 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
623 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200624 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700625
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200626 if (path != null) {
627 //path could be null if we added to the Ptree but didn't push
628 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700629
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200630 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200631 if (path.getUsers() <= 0 && !path.isPermanent()) {
632 deletePath(path);
633 pushedPaths.remove(path.getDstIpAddress());
634 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200635 }
636 }
637 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700638
pingping-linba5c52f2014-02-11 16:52:01 -0800639 // TODO have not tested this module
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200640 private void deletePrefixFlows(Prefix prefix) {
641 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700642
pingping-linba5c52f2014-02-11 16:52:01 -0800643 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
644 for (FlowId flowId : flowIds) {
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700645 // TODO: Delete the flow by using the new Path Intent framework
646 /*
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200647 if (log.isTraceEnabled()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800648 //Trace the flow status by flowPath in the switch before deleting it
649 log.trace("Pushing a DELETE flow mod to flowPath : {}",
650 flowManagerService.getFlow(flowId).toString());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200651 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700652
pingping-linba5c52f2014-02-11 16:52:01 -0800653 if( flowManagerService.deleteFlow(flowId))
654 {
655 log.debug("Successfully deleted FlowId: {}",flowId);
656 }
657 else
658 {
659 log.debug("Failed to delete FlowId: {}",flowId);
660 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700661 */
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200662 }
663 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700664
pingping-linba5c52f2014-02-11 16:52:01 -0800665 // TODO need to record the path and then delete here
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200666 private void deletePath(Path path) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700667 log.debug("Deleting flows for path to {}",
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200668 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700669
pingping-linba5c52f2014-02-11 16:52:01 -0800670 // TODO need update
671 /*for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200672 if (log.isTraceEnabled()) {
673 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
674 new Object[] {HexString.toHexString(pfm.getDpid()),
675 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
676 });
677 }
pingping-linba5c52f2014-02-11 16:52:01 -0800678
Jonathan Hart309889c2013-08-13 23:26:24 +1200679 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
pingping-linba5c52f2014-02-11 16:52:01 -0800680 }*/
Jonathan Hart309889c2013-08-13 23:26:24 +1200681 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700682
683
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200684 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200685 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800686
687 /**
688 * On startup, we need to calculate a full mesh of paths between all gateway
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700689 * switches
690 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200691 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700692 //For each border router, calculate and install a path from every other
693 //border switch to said border router. However, don't install the entry
694 //in to the first hop switch, as we need to install an entry to rewrite
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700695 //for each prefix received. This will be done later when prefixes have
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700696 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700697
Jonathan Hartc824ad02013-07-03 15:58:45 +1200698 for (BgpPeer peer : bgpPeers.values()) {
699 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700700
Jonathan Hart309889c2013-08-13 23:26:24 +1200701 //We know there's not already a Path here pushed, because this is
702 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200703 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200704 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700705
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200706 //See if we know the MAC address of the peer. If not we can't
707 //do anything until we learn it
pingping-linba5c52f2014-02-11 16:52:01 -0800708 MACAddress macAddress;
709 IDeviceObject nextHopDevice =
710 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
711
712 if(nextHopDevice == null){
713 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
714 //Put in the pending paths list first
715 pathsWaitingOnArp.put(peer.getIpAddress(), path);
716 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
717 continue;
718 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700719
pingping-linba5c52f2014-02-11 16:52:01 -0800720 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
721
Jonathan Hartabad6a52013-09-30 18:17:21 +1300722 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200723 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
724 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200725 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200726 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
727 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700728 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700729
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200730 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300731 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700732 }
733 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700734
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200735 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200736 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700737
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200738 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
739 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800740
741 FlowPath flowPath = new FlowPath();
742
743 flowPath.setInstallerId(new CallerId("SDNIP"));
744
745 // Set flowPath FlowPathType and FlowPathUserState
746 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
747 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
748
749 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
750 FlowPathFlags flowPathFlags = new FlowPathFlags();
751 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
752 flowPath.setFlowPathFlags(flowPathFlags);
753
754 // Create the DataPath object: dstSwitchPort
755 SwitchPort dstPort = new SwitchPort();
756 dstPort.setDpid(new Dpid(dstInterface.getDpid()));
757 dstPort.setPort(new Port(dstInterface.getPort()));
758
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200759 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800760
Jonathan Hart45107222013-10-22 17:35:04 -0700761 if (dstInterface.equals(srcInterface)){
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200762 continue;
763 }
pingping-linba5c52f2014-02-11 16:52:01 -0800764
765 // Create flowPath FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800766 flowPath.setFlowId(new FlowId());
767
768 // Create the DataPath object: srcSwitchPort
769 SwitchPort srcPort = new SwitchPort();
770 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
771 srcPort.setPort(new Port(srcInterface.getPort()));
772
773 DataPath dataPath = new DataPath();
774 dataPath.setSrcPort(srcPort);
775 dataPath.setDstPort(dstPort);
776 flowPath.setDataPath(dataPath);
777
778 // Create the Flow Path Match condition(s)
779 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
780 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
781 flowEntryMatch.enableDstMac(dstMacAddress);
782 flowPath.setFlowEntryMatch(flowEntryMatch);
783
784 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
785 // Shortest Path Flow, and is always the last action for the Flow Entries
786 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700787 // TODO: Add the flow by using the new Path Intent framework
788 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800789 if (flowManagerService.addFlow(flowPath) == null) {
790 log.error("Failed to set up MAC based forwarding path to {}, {}",
791 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200792 }
793 else {
pingping-linba5c52f2014-02-11 16:52:01 -0800794 log.debug("Successfully set up MAC based forwarding path to {}, {}",
795 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200796 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700797 */
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200798 }
799 }
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200800
pingping-linba5c52f2014-02-11 16:52:01 -0800801 /**
802 * Pre-actively install all BGP traffic paths from BGP host attachment point
803 * in SDN network to all the virtual gateways to BGP peers in other networks
804 */
805 private void setupBgpPaths(){
806
807 for (BgpPeer bgpPeer : bgpPeers.values()){
808
809 FlowPath flowPath = new FlowPath();
810 flowPath.setInstallerId(new CallerId("SDNIP"));
811
812 // Set flowPath FlowPathType and FlowPathUserState
813 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
814 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
815
816 // Install flow paths between BGPd and its peers
817 // There is no need to set the FlowPathFlags
818 flowPath.setFlowPathFlags(new FlowPathFlags(0));
819
820 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
821
pingping-linba5c52f2014-02-11 16:52:01 -0800822 // Create the Flow Path Match condition(s)
823 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
824 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
825
826 // Match both source address and dest address
827 IPv4Net dstIPv4Net= new IPv4Net(bgpPeer.getIpAddress().getHostAddress()+"/32");
828 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
829
830 IPv4Net srcIPv4Net= new IPv4Net(peerInterface.getIpAddress().getHostAddress()+"/32");
831 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
832
833 // Match TCP protocol
834 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
835
836 // Match destination TCP port
837 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
838 flowPath.setFlowEntryMatch(flowEntryMatch);
839
840 /**
841 * Create the DataPath: BGP -> BGP peer
842 */
843 // Flow path for src-TCP-port
844 DataPath dataPath = new DataPath();
845
846 SwitchPort srcPort = new SwitchPort();
847 srcPort.setDpid(bgpdAttachmentPoint.dpid());
848 srcPort.setPort(bgpdAttachmentPoint.port());
849 dataPath.setSrcPort(srcPort);
850
851 SwitchPort dstPort = new SwitchPort();
852 dstPort.setDpid(new Dpid(peerInterface.getDpid()));
853 dstPort.setPort(new Port(peerInterface.getSwitchPort().port()));
854 dataPath.setDstPort(dstPort);
855
856 flowPath.setDataPath(dataPath);
857
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700858 // TODO: Add the flow by using the new Path Intent framework
859 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800860 if (flowManagerService.addFlow(flowPath) == null) {
861 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
862 bgpPeer.getIpAddress().getHostAddress());
863 }
864 else {
865 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
866 bgpPeer.getIpAddress().getHostAddress());
867 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700868 */
pingping-linba5c52f2014-02-11 16:52:01 -0800869
870 // Disable dst-TCP-port, and set src-TCP-port
871 flowEntryMatch.disableDstTcpUdpPort();
872 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
873 flowPath.setFlowEntryMatch(flowEntryMatch);
874
875 // Create a new FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800876 flowPath.setFlowId(new FlowId());
877
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700878 // TODO: Add the flow by using the new Path Intent framework
879 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800880 if (flowManagerService.addFlow(flowPath) == null) {
881 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
882 bgpPeer.getIpAddress().getHostAddress());
883 }
884 else {
885 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
886 bgpPeer.getIpAddress().getHostAddress());
887 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700888 */
pingping-linba5c52f2014-02-11 16:52:01 -0800889
890 /**
891 * Create the DataPath: BGP <-BGP peer
892 */
893 // Reversed BGP flow path for src-TCP-port
pingping-linba5c52f2014-02-11 16:52:01 -0800894 flowPath.setFlowId(new FlowId());
895
896 DataPath reverse_dataPath = new DataPath();
897
898 SwitchPort reverse_dstPort = new SwitchPort();
899 reverse_dstPort.setDpid(bgpdAttachmentPoint.dpid());
900 reverse_dstPort.setPort(bgpdAttachmentPoint.port());
901 reverse_dataPath.setDstPort(reverse_dstPort);
902
903 SwitchPort reverse_srcPort = new SwitchPort();
904 reverse_srcPort.setDpid(new Dpid(peerInterface.getDpid()));
905 reverse_srcPort.setPort(new Port(peerInterface.getSwitchPort().port()));
906 reverse_dataPath.setSrcPort(reverse_srcPort);
907 flowPath.setDataPath(reverse_dataPath);
908
909 // reverse the dst IP and src IP addresses
910 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
911 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
912 flowPath.setFlowEntryMatch(flowEntryMatch);
913
914 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
915
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700916 // TODO: Add the flow by using the new Path Intent framework
917 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800918 if (flowManagerService.addFlow(flowPath) == null) {
919
920 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
921 bgpPeer.getIpAddress().getHostAddress());
922 }
923 else {
924 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
925 bgpPeer.getIpAddress().getHostAddress());
926 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700927 */
pingping-linba5c52f2014-02-11 16:52:01 -0800928
929 // Reversed BGP flow path for dst-TCP-port
pingping-linba5c52f2014-02-11 16:52:01 -0800930 flowPath.setFlowId(new FlowId());
931
932 // Disable src-TCP-port, and set the dst-TCP-port
933 flowEntryMatch.disableSrcTcpUdpPort();
934 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
935 flowPath.setFlowEntryMatch(flowEntryMatch);
936
937 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700938
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700939 // TODO: Add the flow by using the new Path Intent framework
940 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800941 if (flowManagerService.addFlow(flowPath) == null) {
942 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
943 bgpPeer.getIpAddress().getHostAddress());
944 }
945 else {
946 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
947 bgpPeer.getIpAddress().getHostAddress());
948 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700949 */
pingping-linba5c52f2014-02-11 16:52:01 -0800950
951 /**
952 * ICMP paths between BGPd and its peers
953 */
954 //match ICMP protocol BGP <- Peer
pingping-linba5c52f2014-02-11 16:52:01 -0800955 flowPath.setFlowId(new FlowId());
956
957 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
958 flowEntryMatch.disableSrcTcpUdpPort();
959 flowEntryMatch.disableDstTcpUdpPort();
960
961 flowPath.setFlowEntryMatch(flowEntryMatch);
962
963 flowPath.setDataPath(reverse_dataPath);
964
965 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
966
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700967 // TODO: Add the flow by using the new Path Intent framework
968 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800969 if (flowManagerService.addFlow(flowPath) == null) {
970
971 log.error("Failed to set up ICMP path BGP <- Peer {}",
972 bgpPeer.getIpAddress().getHostAddress());
973 }
974 else {
975 log.debug("Successfully set up ICMP path BGP <- Peer {}",
976 bgpPeer.getIpAddress().getHostAddress());
977 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700978 */
pingping-linba5c52f2014-02-11 16:52:01 -0800979
980 //match ICMP protocol BGP -> Peer
pingping-linba5c52f2014-02-11 16:52:01 -0800981 flowPath.setFlowId(new FlowId());
982
983 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
984 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
985 flowPath.setFlowEntryMatch(flowEntryMatch);
986
987 flowPath.setDataPath(dataPath);
988
989 log.debug("ICMP flowPath: {}", flowPath.toString());
990
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700991 // TODO: Add the flow by using the new Path Intent framework
992 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800993 if (flowManagerService.addFlow(flowPath) == null) {
994
995 log.error("Failed to set up ICMP path BGP -> Peer {}",
996 bgpPeer.getIpAddress().getHostAddress());
997 }
998 else {
999 log.debug("Successfully set up ICMP path BGP -> Peer {}",
1000 bgpPeer.getIpAddress().getHostAddress());
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001001 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -07001002 */
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001003 }
1004 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001005
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001006 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +13001007 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001008 log.debug("Received ARP response: {} => {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +13001009 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001010
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001011 /*
1012 * We synchronize on this to prevent changes to the ptree while we're pushing
1013 * flows to the switches. If the ptree changes, the ptree and switches
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001014 * could get out of sync.
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001015 */
1016 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001017 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001018
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001019 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001020 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001021 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001022 path.getDstInterface().getSwitchPort()});
1023 //These paths should always be to BGP peers. Paths to non-peers are
1024 //handled once the first prefix is ready to push
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001025 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001026 //A path already got pushed to this endpoint while we were waiting
1027 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001028 if (path.isPermanent()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001029 pushedPaths.get(path.getDstIpAddress()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +12001030 }
1031 }
1032 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001033 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001034 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +12001035 }
1036 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001037
Jonathan Hart309889c2013-08-13 23:26:24 +12001038 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001039
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001040 for (RibUpdate update : prefixesToPush) {
1041 //These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001042
1043 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001044 if (rib != null && rib.equals(update.getRibEntry())) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001045 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001046 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001047 //We only push prefix flows if the prefix is still in the ptree
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001048 //and the next hop is the same as our update. The prefix could
1049 //have been removed while we were waiting for the ARP, or the
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001050 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +12001051 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001052 } else {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001053 log.debug("Received ARP response, but {},{} is no longer in ptree",
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001054 update.getPrefix(), update.getRibEntry());
1055 }
1056 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001057 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001058 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001059
pingping-linba5c52f2014-02-11 16:52:01 -08001060 //TODO wait the priority module of the flow Manager
Jonathan Hartc82051c2013-08-24 15:12:20 +12001061 private void setupArpFlows() {
1062 OFMatch match = new OFMatch();
1063 match.setDataLayerType(Ethernet.TYPE_ARP);
1064 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001065
Jonathan Hartc82051c2013-08-24 15:12:20 +12001066 OFFlowMod fm = new OFFlowMod();
1067 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001068
Jonathan Hartc82051c2013-08-24 15:12:20 +12001069 OFActionOutput action = new OFActionOutput();
1070 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1071 action.setMaxLength((short)0xffff);
1072 List<OFAction> actions = new ArrayList<OFAction>(1);
1073 actions.add(action);
1074 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001075
Jonathan Hartc82051c2013-08-24 15:12:20 +12001076 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001077 .setHardTimeout((short)0)
1078 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1079 .setCookie(0)
1080 .setCommand(OFFlowMod.OFPFC_ADD)
1081 .setPriority(ARP_PRIORITY)
Jonathan Hartc82051c2013-08-24 15:12:20 +12001082 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001083
Jonathan Hartc82051c2013-08-24 15:12:20 +12001084 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001085 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +12001086 }
1087 }
pingping-linba5c52f2014-02-11 16:52:01 -08001088 //TODO need update, waiting for the priority feature from flow Manager
Jonathan Hartf886fa12013-09-18 14:46:29 +12001089 private void setupDefaultDropFlows() {
1090 OFFlowMod fm = new OFFlowMod();
1091 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001092 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001093
Jonathan Hartf886fa12013-09-18 14:46:29 +12001094 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001095 .setHardTimeout((short)0)
1096 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1097 .setCookie(0)
1098 .setCommand(OFFlowMod.OFPFC_ADD)
1099 .setPriority((short)0)
Jonathan Hartf886fa12013-09-18 14:46:29 +12001100 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001101
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001102 OFFlowMod fmLLDP;
1103 OFFlowMod fmBDDP;
1104 try {
pingping-linba5c52f2014-02-11 16:52:01 -08001105 fmLLDP = fm.clone();
1106 fmBDDP = fm.clone();
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001107 } catch (CloneNotSupportedException e1) {
1108 log.error("Error cloning flow mod", e1);
1109 return;
1110 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001111
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001112 OFMatch matchLLDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001113 matchLLDP.setDataLayerType((short)0x88cc);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001114 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1115 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001116
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001117 OFMatch matchBDDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001118 matchBDDP.setDataLayerType((short)0x8942);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001119 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1120 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001121
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001122 OFActionOutput action = new OFActionOutput();
1123 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1124 action.setMaxLength((short)0xffff);
1125 List<OFAction> actions = new ArrayList<OFAction>(1);
1126 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001127
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001128 fmLLDP.setActions(actions);
1129 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001130
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001131 fmLLDP.setPriority(ARP_PRIORITY);
1132 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1133 fmBDDP.setPriority(ARP_PRIORITY);
1134 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001135
1136 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
Jonathan Hart1912afc2013-10-11 12:02:44 +13001137 flowModList.add(fm);
1138 flowModList.add(fmLLDP);
1139 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001140
Jonathan Hartf886fa12013-09-18 14:46:29 +12001141 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001142 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001143 }
1144 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001145
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001146 private void beginRouting(){
1147 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov1237e392014-03-20 16:24:06 -07001148 // TODO: Fix for the new Topology Network Graph
1149 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001150
pingping-linba5c52f2014-02-11 16:52:01 -08001151 // Wait Pavlin's API. We need the following functions.
1152 /*setupArpFlows();
1153 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001154
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001155 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001156 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001157
Jonathan Harte7694532013-09-12 12:34:46 +12001158 //Suppress link discovery on external-facing router ports
1159 for (Interface intf : interfaces.values()) {
1160 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1161 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001162
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001163 bgpUpdatesExecutor.execute(new Runnable() {
1164 @Override
1165 public void run() {
1166 doUpdatesThread();
1167 }
1168 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001169 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001170
pingping-linba5c52f2014-02-11 16:52:01 -08001171 // Before inserting the paths for BGP traffic, we should check
1172 // whether all the switches in the configure file are discovered by onos.
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001173 private void checkSwitchesConnected(){
1174 for (String dpid : switches){
pingping-linba5c52f2014-02-11 16:52:01 -08001175 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1176 getActiveSwitches().iterator();
1177 while(activeSwitches.hasNext())
1178 {
1179 ISwitchObject switchObject = activeSwitches.next();
1180 if (switchObject.getDPID().equals(dpid)) {
1181 break;
1182 }
1183 if(activeSwitches.hasNext() == false) {
1184 log.debug("Not all switches are here yet");
1185 return;
1186 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001187 }
1188 }
1189 switchesConnected = true;
1190 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001191
Jonathan Hartc824ad02013-07-03 15:58:45 +12001192 //Actually we only need to go half way round to verify full mesh connectivity
1193 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001194 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001195 for (Interface dstInterface : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001196 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -07001197 if (dstInterface.equals(srcInterface)) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001198 continue;
1199 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001200
Pavlin Radoslavov1237e392014-03-20 16:24:06 -07001201 // TODO: Fix for the new Topology Network Graph
1202 /*
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001203 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001204 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001205
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001206 if (shortestPath == null){
1207 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001208 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001209 return;
1210 }
Pavlin Radoslavov1237e392014-03-20 16:24:06 -07001211 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001212 }
1213 }
1214 topologyReady = true;
1215 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001216
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001217 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001218 if (!switchesConnected){
1219 checkSwitchesConnected();
1220 }
1221 boolean oldTopologyReadyStatus = topologyReady;
1222 if (switchesConnected && !topologyReady){
1223 checkTopologyReady();
1224 }
1225 if (!oldTopologyReadyStatus && topologyReady){
1226 beginRouting();
1227 }
1228 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001229
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001230 private void doUpdatesThread() {
1231 boolean interrupted = false;
1232 try {
1233 while (true) {
1234 try {
1235 RibUpdate update = ribUpdates.take();
1236 switch (update.getOperation()){
1237 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001238 if (validateUpdate(update)) {
1239 processRibAdd(update);
1240 }
1241 else {
1242 log.debug("Rib UPDATE out of order: {} via {}",
1243 update.getPrefix(), update.getRibEntry().getNextHop());
1244 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001245 break;
1246 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001247 if (validateUpdate(update)) {
1248 processRibDelete(update);
1249 }
1250 else {
1251 log.debug("Rib DELETE out of order: {} via {}",
1252 update.getPrefix(), update.getRibEntry().getNextHop());
1253 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001254 break;
1255 }
1256 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001257 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001258 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001259 } catch (Exception e) {
1260 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001261 }
1262 }
1263 } finally {
1264 if (interrupted) {
1265 Thread.currentThread().interrupt();
1266 }
1267 }
1268 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001269
Jonathan Harte4c98692013-10-18 17:40:03 -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
Jonathan Harte4c98692013-10-18 17:40:03 -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
Jonathan Harte4c98692013-10-18 17:40:03 -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
Jonathan Harte4c98692013-10-18 17:40:03 -07001288 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1289 return true;
1290 }
1291 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1292 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1293 return true;
1294 }
1295 else {
1296 return false;
1297 }
1298 }
1299 else {
1300 return false;
1301 }
1302 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001303
1304 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001305 public void topologyChanged() {
1306 if (topologyReady) {
1307 return;
1308 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001309
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001310 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001311 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001312 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1313 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001314 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001315 refreshNeeded = true;
1316 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001317
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001318 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001319
Jonathan Hart98957bf2013-07-01 14:49:24 +12001320 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1321 synchronized (linkUpdates) {
1322 linkUpdates.add(ldu);
1323 }
1324 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001325 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001326
Jonathan Hart64c0b202013-08-20 15:45:07 +12001327 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001328 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001329 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001330 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001331
1332 @Override
1333 public void addedSwitch(IOFSwitch sw) {
1334 if (!topologyReady) {
1335 sw.clearAllFlowMods();
1336 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001337
Jonathan Hart1912afc2013-10-11 12:02:44 +13001338 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001339 }
1340
1341 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001342 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001343
1344 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001345 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001346
1347 @Override
1348 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001349 return "BgpRoute";
1350 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001351
Jonathan Hart08ee8522013-09-22 17:34:43 +12001352 /*
Jonathan Harta8887642013-10-28 13:46:54 -07001353 * IConfigInfoService methods
Jonathan Hart08ee8522013-09-22 17:34:43 +12001354 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001355
Jonathan Hart08ee8522013-09-22 17:34:43 +12001356 @Override
1357 public boolean isInterfaceAddress(InetAddress address) {
1358 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1359 return (intf != null && intf.getIpAddress().equals(address));
1360 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001361
Jonathan Hart08ee8522013-09-22 17:34:43 +12001362 @Override
1363 public boolean inConnectedNetwork(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
Jonathan Hart08ee8522013-09-22 17:34:43 +12001368 @Override
1369 public boolean fromExternalNetwork(long inDpid, short inPort) {
1370 for (Interface intf : interfaces.values()) {
1371 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1372 return true;
1373 }
1374 }
1375 return false;
1376 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001377
Jonathan Hart08ee8522013-09-22 17:34:43 +12001378 @Override
1379 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1380 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1381 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001382
Jonathan Hart08ee8522013-09-22 17:34:43 +12001383 @Override
1384 public boolean hasLayer3Configuration() {
1385 return !interfaces.isEmpty();
1386 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001387
Jonathan Hart08ee8522013-09-22 17:34:43 +12001388 @Override
1389 public MACAddress getRouterMacAddress() {
1390 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001391 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001392
Jonathan Harta8887642013-10-28 13:46:54 -07001393 @Override
1394 public short getVlan() {
1395 return vlan;
1396 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001397}