2 * Copyright (C) 2014 Red Hat, Inc.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 * Authors : Dave Tucker, Flavio Fernandes
10 package org.opendaylight.ovsdb.openstack.netvirt.impl;
12 import org.apache.commons.lang3.tuple.ImmutablePair;
13 import org.apache.commons.lang3.tuple.Pair;
14 import org.opendaylight.neutron.spi.INeutronNetworkCRUD;
15 import org.opendaylight.neutron.spi.INeutronPortCRUD;
16 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
17 import org.opendaylight.neutron.spi.NeutronFloatingIP;
18 import org.opendaylight.neutron.spi.NeutronNetwork;
19 import org.opendaylight.neutron.spi.NeutronPort;
20 import org.opendaylight.neutron.spi.NeutronRouter;
21 import org.opendaylight.neutron.spi.NeutronRouter_Interface;
22 import org.opendaylight.neutron.spi.NeutronSubnet;
23 import org.opendaylight.neutron.spi.Neutron_IPs;
24 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
25 import org.opendaylight.ovsdb.openstack.netvirt.api.*;
26 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
29 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
31 import com.google.common.base.Preconditions;
32 import org.osgi.framework.BundleContext;
33 import org.osgi.framework.ServiceReference;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
37 import java.net.InetAddress;
38 import java.net.UnknownHostException;
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.ArrayList;
42 import java.util.List;
47 * Neutron L3 Adapter implements a hub-like adapter for the various Neutron events. Based on
48 * these events, the abstract router callbacks can be generated to the multi-tenant aware router,
49 * as well as the multi-tenant router forwarding provider.
51 public class NeutronL3Adapter implements ConfigInterface {
52 static final Logger logger = LoggerFactory.getLogger(NeutronL3Adapter.class);
54 // The implementation for each of these services is resolved by the OSGi Service Manager
55 private volatile ConfigurationService configurationService;
56 private volatile TenantNetworkManager tenantNetworkManager;
57 private volatile NodeCacheManager nodeCacheManager;
58 private volatile INeutronNetworkCRUD neutronNetworkCache;
59 private volatile INeutronSubnetCRUD neutronSubnetCache;
60 private volatile INeutronPortCRUD neutronPortCache;
61 private volatile L3ForwardingProvider l3ForwardingProvider;
62 private volatile InboundNatProvider inboundNatProvider;
63 private volatile OutboundNatProvider outboundNatProvider;
64 private volatile ArpProvider arpProvider;
65 private volatile RoutingProvider routingProvider;
67 private class FloatIpData {
68 FloatIpData(final Long dpid, final Long ofPort, final String segId, final String macAddress,
69 final String floatingIpAddress, final String fixedIpAddress) {
73 this.macAddress = macAddress;
74 this.floatingIpAddress = floatingIpAddress;
75 this.fixedIpAddress = fixedIpAddress;
78 public final Long dpid;
79 public final Long ofPort;
80 public final String segId;
81 public final String macAddress;
82 public final String floatingIpAddress;
83 public final String fixedIpAddress;
86 private Set<String> inboundIpRewriteCache;
87 private Set<String> outboundIpRewriteCache;
88 private Set<String> outboundIpRewriteExclusionCache;
89 private Set<String> routerInterfacesCache;
90 private Set<String> staticArpEntryCache;
91 private Set<String> l3ForwardingCache;
92 private Set<String> defaultRouteCache;
93 private Map<String, String> networkIdToRouterMacCache;
94 private Map<String, List<Neutron_IPs>> networkIdToRouterIpListCache;
95 private Map<String, NeutronRouter_Interface> subnetIdToRouterInterfaceCache;
96 private Map<String, Pair<Long, Uuid>> neutronPortToDpIdCache;
97 private Map<String, FloatIpData> floatIpDataMapCache;
98 private Boolean enabled = false;
99 private Boolean flgDistributedARPEnabled = true;
100 private Southbound southbound;
102 final static String OWNER_ROUTER_INTERFACE = "network:router_interface";
103 final static String OWNER_ROUTER_INTERFACE_DISTRIBUTED = "network:router_interface_distributed";
104 final static String OWNER_ROUTER_GATEWAY = "network:router_gateway";
105 final static String OWNER_FLOATING_IP = "network:floatingip";
107 public NeutronL3Adapter() {
108 logger.info(">>>>>> NeutronL3Adapter constructor {}", this.getClass());
111 private void initL3AdapterMembers() {
112 Preconditions.checkNotNull(configurationService);
114 if (configurationService.isL3ForwardingEnabled()) {
115 this.inboundIpRewriteCache = new HashSet<>();
116 this.outboundIpRewriteCache = new HashSet<>();
117 this.outboundIpRewriteExclusionCache = new HashSet<>();
118 this.routerInterfacesCache = new HashSet<>();
119 this.staticArpEntryCache = new HashSet<>();
120 this.l3ForwardingCache = new HashSet<>();
121 this.defaultRouteCache = new HashSet<>();
122 this.networkIdToRouterMacCache = new HashMap<>();
123 this.networkIdToRouterIpListCache = new HashMap<>();
124 this.subnetIdToRouterInterfaceCache = new HashMap<>();
125 this.neutronPortToDpIdCache = new HashMap<>();
126 this.floatIpDataMapCache = new HashMap<>();
129 logger.info("OVSDB L3 forwarding is enabled");
130 if (configurationService.isDistributedArpDisabled()) {
131 this.flgDistributedARPEnabled = false;
132 logger.info("Distributed ARP responder is disabled");
134 logger.debug("Distributed ARP responder is enabled");
137 logger.debug("OVSDB L3 forwarding is disabled");
142 // Callbacks from OVSDB's northbound handlers
145 public void handleNeutronSubnetEvent(final NeutronSubnet subnet, Action action) {
146 logger.debug("Neutron subnet {} event : {}", action, subnet.toString());
151 public void handleNeutronPortEvent(final NeutronPort neutronPort, Action action) {
152 logger.debug("Neutron port {} event : {}", action, neutronPort.toString());
156 final boolean isDelete = action == Action.DELETE;
158 // Treat the port event as a router interface event if the port belongs to router. This is a
159 // helper for handling cases when handleNeutronRouterInterfaceEvent is not available
161 if (neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_INTERFACE) ||
162 neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_INTERFACE_DISTRIBUTED)) {
163 for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
164 NeutronRouter_Interface neutronRouterInterface =
165 new NeutronRouter_Interface(neutronIP.getSubnetUUID(), neutronPort.getPortUUID());
166 neutronRouterInterface.setID(neutronIP.getSubnetUUID()); // id of router interface to be same as subnet
167 neutronRouterInterface.setTenantID(neutronPort.getTenantID());
169 this.handleNeutronRouterInterfaceEvent(null /*neutronRouter*/, neutronRouterInterface, action);
172 // We made it here, port is not used as a router interface. If this is not a delete action, make sure that
173 // all nodes that are supposed to have a router interface for the port's subnet(s), have it configured. We
174 // need to do this check here because a router interface is not added to a node until tenant becomes needed
178 for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
179 NeutronRouter_Interface neutronRouterInterface =
180 subnetIdToRouterInterfaceCache.get(neutronIP.getSubnetUUID());
181 if (neutronRouterInterface != null) {
182 this.handleNeutronRouterInterfaceEvent(null /*neutronRouter*/, neutronRouterInterface, action);
186 this.updateL3ForNeutronPort(neutronPort, isDelete);
190 public void handleNeutronRouterEvent(final NeutronRouter neutronRouter, Action action) {
191 logger.debug("Neutron router {} event : {}", action, neutronRouter.toString());
196 public void handleNeutronRouterInterfaceEvent(final NeutronRouter neutronRouter,
197 final NeutronRouter_Interface neutronRouterInterface,
199 logger.debug("Router interface {} got event {}. Subnet {}",
200 neutronRouterInterface.getPortUUID(),
202 neutronRouterInterface.getSubnetUUID());
206 final boolean isDelete = action == Action.DELETE;
208 this.programFlowsForNeutronRouterInterface(neutronRouterInterface, isDelete);
210 // As neutron router interface is added/removed, we need to iterate through all the neutron ports and
211 // see if they are affected by l3
213 for (NeutronPort neutronPort : neutronPortCache.getAllPorts()) {
214 boolean currPortShouldBeDeleted = false;
215 // Note: delete in this case only applies to 1)router interface delete and 2)ports on the same subnet
217 for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
218 if (neutronRouterInterface.getSubnetUUID().equalsIgnoreCase(neutronIP.getSubnetUUID())) {
219 currPortShouldBeDeleted = true;
224 this.updateL3ForNeutronPort(neutronPort, currPortShouldBeDeleted);
228 public void handleNeutronFloatingIPEvent(final NeutronFloatingIP neutronFloatingIP,
230 Preconditions.checkNotNull(neutronFloatingIP);
232 logger.debug(" Floating IP {} {}<->{}, network uuid {}", action,
233 neutronFloatingIP.getFixedIPAddress(),
234 neutronFloatingIP.getFloatingIPAddress(),
235 neutronFloatingIP.getFloatingNetworkUUID());
239 // Consider action to be delete if getFixedIPAddress is null
241 if (neutronFloatingIP.getFixedIPAddress() == null) {
242 action = Action.DELETE;
245 // this.programFlowsForFloatingIP(neutronFloatingIP, action == Action.DELETE);
247 if (action != Action.DELETE) {
248 programFlowsForFloatingIPArpAdd(neutronFloatingIP); // must be first, as it updates floatIpDataMapCache
250 programFlowsForFloatingIPInbound(neutronFloatingIP, Action.ADD);
252 programFlowsForFloatingIPInbound(neutronFloatingIP, Action.DELETE);
254 programFlowsForFloatingIPArpDelete(neutronFloatingIP.getID()); // must be last, as it updates floatIpDataMapCache
258 private void programFlowsForFloatingIPInbound(final NeutronFloatingIP neutronFloatingIP, final Action action) {
259 Preconditions.checkNotNull(neutronFloatingIP);
261 final FloatIpData fid = floatIpDataMapCache.get(neutronFloatingIP.getID());
263 logger.trace("programFlowsForFloatingIPInboundAdd {} for {} uuid {} not in local cache",
264 action, neutronFloatingIP.getFloatingIPAddress(), neutronFloatingIP.getID());
267 programInboundIpRewriteStage1(fid.dpid, fid.ofPort, fid.segId, fid.floatingIpAddress, fid.fixedIpAddress,
271 private void programFlowsForFloatingIPArpAdd(final NeutronFloatingIP neutronFloatingIP) {
272 Preconditions.checkNotNull(neutronFloatingIP);
273 Preconditions.checkNotNull(neutronFloatingIP.getFixedIPAddress());
274 Preconditions.checkNotNull(neutronFloatingIP.getFloatingIPAddress());
276 if (floatIpDataMapCache.get(neutronFloatingIP.getID()) != null) {
277 logger.trace("programFlowsForFloatingIPArpAdd for neutronFloatingIP {} uuid {} is already done",
278 neutronFloatingIP.getFloatingIPAddress(), neutronFloatingIP.getID());
282 // find bridge Node where floating ip is configured by looking up cache for its port
283 final NeutronPort neutronPortForFloatIp = findNeutronPortForFloatingIp(neutronFloatingIP.getID());
284 final String neutronTenantPortUuid = neutronFloatingIP.getPortUUID();
285 final Pair<Long, Uuid> nodeIfPair = neutronPortToDpIdCache.get(neutronTenantPortUuid);
286 final String floatingIpMac = neutronPortForFloatIp == null ? null : neutronPortForFloatIp.getMacAddress();
287 final String fixedIpAddress = neutronFloatingIP.getFixedIPAddress();
288 final String floatingIpAddress = neutronFloatingIP.getFloatingIPAddress();
290 final NeutronPort tenantNeutronPort = neutronPortCache.getPort(neutronTenantPortUuid);
291 final NeutronNetwork tenantNeutronNetwork = tenantNeutronPort != null ?
292 neutronNetworkCache.getNetwork(tenantNeutronPort.getNetworkUUID()) : null;
293 final String providerSegmentationId = tenantNeutronNetwork != null ?
294 tenantNeutronNetwork.getProviderSegmentationID() : null;
296 if (nodeIfPair == null || neutronTenantPortUuid == null ||
297 providerSegmentationId == null || providerSegmentationId.isEmpty() ||
298 floatingIpMac == null || floatingIpMac.isEmpty()) {
299 logger.trace("Floating IP {}<->{}, found no dpid for floatPort {} tenantPortUuid {} seg {} mac {}",
302 neutronPortForFloatIp,
303 neutronTenantPortUuid,
304 providerSegmentationId,
309 // get ofport for patch port in br-int
310 final Long dpId = nodeIfPair.getLeft();
311 final Long ofPort = findOFPortForExtPatch(dpId);
312 if (ofPort == null) {
313 logger.warn("Unable to locate OF port of patch port to connect floating ip to external bridge. dpid {}",
318 // Respond to ARPs for the floating ip address by default, via the patch port that connects br-int to br-ex
320 if (programStaticArpStage1(dpId, encodeExcplicitOFPort(ofPort), floatingIpMac, floatingIpAddress,
322 final FloatIpData floatIpData = new FloatIpData(dpId, ofPort, providerSegmentationId, floatingIpMac,
323 floatingIpAddress, fixedIpAddress);
324 floatIpDataMapCache.put(neutronFloatingIP.getID(), floatIpData);
325 logger.info("Floating IP {}<->{} programmed ARP mac {} on OFport {} seg {} dpid {}",
326 neutronFloatingIP.getFixedIPAddress(), neutronFloatingIP.getFloatingIPAddress(),
327 floatingIpMac, ofPort, providerSegmentationId, dpId);
331 private void programFlowsForFloatingIPArpDelete(final String neutronFloatingIPUuid) {
332 final FloatIpData floatIpData = floatIpDataMapCache.get(neutronFloatingIPUuid);
333 if (floatIpData == null) {
334 logger.trace("programFlowsForFloatingIPArpDelete for uuid {} is not needed", neutronFloatingIPUuid);
338 if (programStaticArpStage1(floatIpData.dpid, encodeExcplicitOFPort(floatIpData.ofPort), floatIpData.macAddress,
339 floatIpData.floatingIpAddress, Action.DELETE)) {
340 floatIpDataMapCache.remove(neutronFloatingIPUuid);
341 logger.info("Floating IP {} un-programmed ARP mac {} on {} dpid {}",
342 floatIpData.floatingIpAddress, floatIpData.macAddress, floatIpData.ofPort, floatIpData.dpid);
346 private final NeutronPort findNeutronPortForFloatingIp(final String floatingIpUuid) {
347 for (NeutronPort neutronPort : neutronPortCache.getAllPorts()) {
348 if (neutronPort.getDeviceOwner().equals(OWNER_FLOATING_IP) &&
349 neutronPort.getDeviceID().equals(floatingIpUuid)) {
356 private final Long findOFPortForExtPatch(Long dpId) {
357 final String brInt = configurationService.getIntegrationBridgeName();
358 final String brExt = configurationService.getExternalBridgeName();
359 final String portNameInt = configurationService.getPatchPortName(new ImmutablePair<>(brInt, brExt));
361 Preconditions.checkNotNull(dpId);
362 Preconditions.checkNotNull(portNameInt);
364 final long dpidPrimitive = dpId.longValue();
365 for (Node node : nodeCacheManager.getBridgeNodes()) {
366 if (dpidPrimitive == southbound.getDataPathId(node)) {
367 final OvsdbTerminationPointAugmentation terminationPointOfBridge =
368 southbound.getTerminationPointOfBridge(node, portNameInt);
369 return terminationPointOfBridge == null ? null : terminationPointOfBridge.getOfport();
375 public void handleNeutronNetworkEvent(final NeutronNetwork neutronNetwork, Action action) {
376 logger.debug("neutronNetwork {}: network: {}", action, neutronNetwork);
382 // Callbacks from OVSDB's southbound handler
384 public void handleInterfaceEvent(final Node bridgeNode, final OvsdbTerminationPointAugmentation intf,
385 final NeutronNetwork neutronNetwork, Action action) {
386 logger.debug("southbound interface {} node:{} interface:{}, neutronNetwork:{}",
387 action, bridgeNode.getNodeId().getValue(), intf.getName(), neutronNetwork);
392 final NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
393 final Long dpId = getDpidForIntegrationBridge(bridgeNode);
394 final Uuid interfaceUuid = intf.getInterfaceUuid();
396 logger.trace("southbound interface {} node:{} interface:{}, neutronNetwork:{} port:{} dpid:{} intfUuid:{}",
397 action, bridgeNode.getNodeId().getValue(), intf.getName(), neutronNetwork, neutronPort, dpId, interfaceUuid);
399 if (neutronPort != null) {
400 final String neutronPortUuid = neutronPort.getPortUUID();
402 if (action != Action.DELETE && neutronPortToDpIdCache.get(neutronPortUuid) == null &&
403 dpId != null && interfaceUuid != null) {
404 handleInterfaceEventAdd(neutronPortUuid, dpId, interfaceUuid);
407 handleNeutronPortEvent(neutronPort, action);
410 if (action == Action.DELETE && interfaceUuid != null) {
411 handleInterfaceEventDelete(intf, dpId);
415 private void handleInterfaceEventAdd(final String neutronPortUuid, Long dpId, final Uuid interfaceUuid) {
416 neutronPortToDpIdCache.put(neutronPortUuid, new ImmutablePair<>(dpId, interfaceUuid));
417 logger.debug("handleInterfaceEvent add cache entry NeutronPortUuid {} : dpid {}, ifUuid {}",
418 neutronPortUuid, dpId, interfaceUuid.getValue());
421 private void handleInterfaceEventDelete(final OvsdbTerminationPointAugmentation intf, final Long dpId) {
422 // Remove entry from neutronPortToDpIdCache based on interface uuid
423 for (Map.Entry<String, Pair<Long, Uuid>> entry : neutronPortToDpIdCache.entrySet()) {
424 final String currPortUuid = entry.getKey();
425 if (intf.getInterfaceUuid().equals(entry.getValue().getRight())) {
426 logger.debug("handleInterfaceEventDelete remove cache entry NeutronPortUuid {} : dpid {}, ifUuid {}",
427 currPortUuid, dpId, intf.getInterfaceUuid().getValue());
428 neutronPortToDpIdCache.remove(currPortUuid);
437 private void updateL3ForNeutronPort(final NeutronPort neutronPort, final boolean isDelete) {
439 final String networkUUID = neutronPort.getNetworkUUID();
440 final String routerMacAddress = networkIdToRouterMacCache.get(networkUUID);
442 // If there is no router interface handling the networkUUID, we are done
443 if (routerMacAddress == null || routerMacAddress.isEmpty()) {
447 // If this is the neutron port for the router interface itself, ignore it as well. Ports that represent the
448 // router interface are handled via handleNeutronRouterInterfaceEvent.
449 if (routerMacAddress.equalsIgnoreCase(neutronPort.getMacAddress())) {
453 final NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(networkUUID);
454 final String providerSegmentationId = neutronNetwork != null ?
455 neutronNetwork.getProviderSegmentationID() : null;
456 final String tenantMac = neutronPort.getMacAddress();
458 if (providerSegmentationId == null || providerSegmentationId.isEmpty() ||
459 tenantMac == null || tenantMac.isEmpty()) {
460 return; // done: go no further w/out all the info needed...
463 final Action action = isDelete ? Action.DELETE : Action.ADD;
464 List<Node> nodes = nodeCacheManager.getBridgeNodes();
465 if (nodes.isEmpty()) {
466 logger.trace("updateL3ForNeutronPort has no nodes to work with");
468 for (Node node : nodes) {
469 final Long dpid = getDpidForIntegrationBridge(node);
474 for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
475 final String tenantIpStr = neutronIP.getIpAddress();
476 if (tenantIpStr.isEmpty()) {
480 // Configure L3 fwd. We do that regardless of tenant network present, because these rules are
481 // still needed when routing to subnets non-local to node (bug 2076).
482 programL3ForwardingStage1(node, dpid, providerSegmentationId, tenantMac, tenantIpStr, action);
484 // Configure distributed ARP responder
485 if (true == flgDistributedARPEnabled) {
486 programStaticArpStage1(dpid, providerSegmentationId, tenantMac, tenantIpStr, action);
492 private void programL3ForwardingStage1(Node node, Long dpid, String providerSegmentationId,
493 String macAddress, String ipStr,
494 Action actionForNode) {
495 // Based on the local cache, figure out whether programming needs to occur. To do this, we
496 // will look at desired action for node.
498 final String cacheKey = node.getNodeId().getValue() + ":" + providerSegmentationId + ":" + ipStr;
499 final Boolean isProgrammed = l3ForwardingCache.contains(cacheKey);
501 if (actionForNode == Action.DELETE && isProgrammed == Boolean.FALSE) {
502 logger.trace("programL3ForwardingStage1 for node {} providerId {} mac {} ip {} action {} is already done",
503 node.getNodeId().getValue(), providerSegmentationId, macAddress, ipStr, actionForNode);
506 if (actionForNode == Action.ADD && isProgrammed == Boolean.TRUE) {
507 logger.trace("programL3ForwardingStage1 for node {} providerId {} mac {} ip {} action {} is already done",
508 node.getNodeId().getValue(), providerSegmentationId, macAddress, ipStr, actionForNode);
512 Status status = this.programL3ForwardingStage2(node, dpid, providerSegmentationId,
513 macAddress, ipStr, actionForNode);
514 if (status.isSuccess()) {
516 if (actionForNode == Action.ADD) {
517 l3ForwardingCache.add(cacheKey);
519 l3ForwardingCache.remove(cacheKey);
524 private Status programL3ForwardingStage2(Node node, Long dpid, String providerSegmentationId,
527 Action actionForNode) {
530 InetAddress inetAddress = InetAddress.getByName(address);
531 status = l3ForwardingProvider == null ?
532 new Status(StatusCode.SUCCESS) :
533 l3ForwardingProvider.programForwardingTableEntry(dpid, providerSegmentationId,
534 inetAddress, macAddress, actionForNode);
535 } catch (UnknownHostException e) {
536 status = new Status(StatusCode.BADREQUEST);
539 if (status.isSuccess()) {
540 logger.debug("ProgramL3Forwarding {} for mac:{} addr:{} node:{} action:{}",
541 l3ForwardingProvider == null ? "skipped" : "programmed",
542 macAddress, address, node.getNodeId().getValue(), actionForNode);
544 logger.error("ProgramL3Forwarding failed for mac:{} addr:{} node:{} action:{} status:{}",
545 macAddress, address, node.getNodeId().getValue(), actionForNode, status);
552 private void programFlowsForNeutronRouterInterface(final NeutronRouter_Interface destNeutronRouterInterface,
554 Preconditions.checkNotNull(destNeutronRouterInterface);
556 final NeutronPort neutronPort = neutronPortCache.getPort(destNeutronRouterInterface.getPortUUID());
557 String macAddress = neutronPort != null ? neutronPort.getMacAddress() : null;
558 List<Neutron_IPs> ipList = neutronPort != null ? neutronPort.getFixedIPs() : null;
559 final NeutronSubnet subnet = neutronSubnetCache.getSubnet(destNeutronRouterInterface.getSubnetUUID());
560 final NeutronNetwork neutronNetwork = subnet != null ?
561 neutronNetworkCache.getNetwork(subnet.getNetworkUUID()) : null;
562 final String destinationSegmentationId = neutronNetwork != null ?
563 neutronNetwork.getProviderSegmentationID() : null;
564 final String gatewayIp = subnet != null ? subnet.getGatewayIP() : null;
565 final Boolean isExternal = neutronNetwork != null ? neutronNetwork.getRouterExternal() : Boolean.TRUE;
566 final String cidr = subnet != null ? subnet.getCidr() : null;
567 final int mask = getMaskLenFromCidr(cidr);
569 logger.trace("programFlowsForNeutronRouterInterface called for interface {} isDelete {}",
570 destNeutronRouterInterface, isDelete);
572 // in delete path, mac address as well as ip address are not provided. Being so, let's find them from
574 if (neutronNetwork != null) {
575 if (macAddress == null || macAddress.isEmpty()) {
576 macAddress = networkIdToRouterMacCache.get(neutronNetwork.getNetworkUUID());
578 if (ipList == null || ipList.isEmpty()) {
579 ipList = networkIdToRouterIpListCache.get(neutronNetwork.getNetworkUUID());
583 if (destinationSegmentationId == null || destinationSegmentationId.isEmpty() ||
584 cidr == null || cidr.isEmpty() ||
585 macAddress == null || macAddress.isEmpty() ||
586 ipList == null || ipList.isEmpty()) {
587 logger.debug("programFlowsForNeutronRouterInterface is bailing seg:{} cidr:{} mac:{} ip:{}",
588 destinationSegmentationId, cidr, macAddress, ipList);
589 return; // done: go no further w/out all the info needed...
592 final Action actionForNode = isDelete ? Action.DELETE : Action.ADD;
594 // Keep cache for finding router's mac from network uuid -- add
597 networkIdToRouterMacCache.put(neutronNetwork.getNetworkUUID(), macAddress);
598 networkIdToRouterIpListCache.put(neutronNetwork.getNetworkUUID(), new ArrayList<>(ipList));
599 subnetIdToRouterInterfaceCache.put(subnet.getSubnetUUID(), destNeutronRouterInterface);
602 List<Node> nodes = nodeCacheManager.getBridgeNodes();
603 if (nodes.isEmpty()) {
604 logger.trace("programFlowsForNeutronRouterInterface has no nodes to work with");
606 for (Node node : nodes) {
607 final Long dpid = getDpidForIntegrationBridge(node);
612 for (Neutron_IPs neutronIP : ipList) {
613 final String ipStr = neutronIP.getIpAddress();
614 if (ipStr.isEmpty()) {
615 logger.debug("programFlowsForNeutronRouterInterface is skipping node {} ip {}",
616 node.getNodeId().getValue(), ipStr);
620 // Iterate through all other interfaces and add/remove reflexive flows to this interface
622 for (NeutronRouter_Interface srcNeutronRouterInterface : subnetIdToRouterInterfaceCache.values()) {
623 programFlowsForNeutronRouterInterfacePair(node, dpid,
624 srcNeutronRouterInterface, destNeutronRouterInterface,
625 neutronNetwork, destinationSegmentationId,
626 macAddress, ipStr, mask, actionForNode,
627 true /*isReflexsive*/);
631 programFlowForNetworkFromExternal(node, dpid, destinationSegmentationId, macAddress, ipStr, mask,
634 // Enable ARP responder by default, because router interface needs to be responded always.
635 programStaticArpStage1(dpid, destinationSegmentationId, macAddress, ipStr, actionForNode);
638 // Compute action to be programmed. In the case of rewrite exclusions, we must never program rules
639 // for the external neutron networks.
642 final Action actionForRewriteExclusion = isExternal ? Action.DELETE : actionForNode;
643 programIpRewriteExclusionStage1(node, dpid, destinationSegmentationId, cidr, actionForRewriteExclusion);
646 // Default route. For non-external subnet, make sure that there is none configured.
648 if (gatewayIp != null && !gatewayIp.isEmpty()) {
649 final Action actionForNodeDefaultRoute =
650 isExternal ? actionForNode : Action.DELETE;
651 final String defaultGatewayMacAddress = configurationService.getDefaultGatewayMacAddress(node);
652 programDefaultRouteStage1(node, dpid, destinationSegmentationId, defaultGatewayMacAddress, gatewayIp,
653 actionForNodeDefaultRoute);
657 // Keep cache for finding router's mac from network uuid -- remove
660 networkIdToRouterMacCache.remove(neutronNetwork.getNetworkUUID());
661 networkIdToRouterIpListCache.remove(neutronNetwork.getNetworkUUID());
662 subnetIdToRouterInterfaceCache.remove(subnet.getSubnetUUID());
666 private void programFlowForNetworkFromExternal(final Node node,
668 final String destinationSegmentationId,
669 final String dstMacAddress,
670 final String destIpStr,
672 final Action actionForNode) {
673 programRouterInterfaceStage1(node, dpid, Constants.EXTERNAL_NETWORK, destinationSegmentationId,
674 dstMacAddress, destIpStr, destMask, actionForNode);
677 private void programFlowsForNeutronRouterInterfacePair(final Node node,
679 final NeutronRouter_Interface srcNeutronRouterInterface,
680 final NeutronRouter_Interface dstNeutronRouterInterface,
681 final NeutronNetwork dstNeutronNetwork,
682 final String destinationSegmentationId,
683 final String dstMacAddress,
684 final String destIpStr,
686 final Action actionForNode,
687 Boolean isReflexsive) {
688 Preconditions.checkNotNull(srcNeutronRouterInterface);
689 Preconditions.checkNotNull(dstNeutronRouterInterface);
691 final String sourceSubnetId = srcNeutronRouterInterface.getSubnetUUID();
692 if (sourceSubnetId == null) {
693 logger.error("Could not get provider Subnet ID from router interface {}",
694 srcNeutronRouterInterface.getID());
698 final NeutronSubnet sourceSubnet = neutronSubnetCache.getSubnet(sourceSubnetId);
699 final String sourceNetworkId = sourceSubnet == null ? null : sourceSubnet.getNetworkUUID();
700 if (sourceNetworkId == null) {
701 logger.error("Could not get provider Network ID from subnet {}", sourceSubnetId);
705 final NeutronNetwork sourceNetwork = neutronNetworkCache.getNetwork(sourceNetworkId);
706 if (sourceNetwork == null) {
707 logger.error("Could not get provider Network for Network ID {}", sourceNetworkId);
711 if (! sourceNetwork.getTenantID().equals(dstNeutronNetwork.getTenantID())) {
712 // Isolate subnets from different tenants within the same router
715 final String sourceSegmentationId = sourceNetwork.getProviderSegmentationID();
716 if (sourceSegmentationId == null) {
717 logger.error("Could not get provider Segmentation ID for Subnet {}", sourceSubnetId);
720 if (sourceSegmentationId.equals(destinationSegmentationId)) {
725 programRouterInterfaceStage1(node, dpid, sourceSegmentationId, destinationSegmentationId,
726 dstMacAddress, destIpStr, destMask, actionForNode);
728 // Flip roles src->dst; dst->src
730 final NeutronPort sourceNeutronPort = neutronPortCache.getPort(srcNeutronRouterInterface.getPortUUID());
731 final String macAddress2 = sourceNeutronPort != null ? sourceNeutronPort.getMacAddress() : null;
732 final List<Neutron_IPs> ipList2 = sourceNeutronPort != null ? sourceNeutronPort.getFixedIPs() : null;
733 final String cidr2 = sourceSubnet.getCidr();
734 final int mask2 = getMaskLenFromCidr(cidr2);
736 if (cidr2 == null || cidr2.isEmpty() ||
737 macAddress2 == null || macAddress2.isEmpty() ||
738 ipList2 == null || ipList2.isEmpty()) {
739 logger.trace("programFlowsForNeutronRouterInterfacePair reflexive is bailing seg:{} cidr:{} mac:{} ip:{}",
740 sourceSegmentationId, cidr2, macAddress2, ipList2);
741 return; // done: go no further w/out all the info needed...
744 for (Neutron_IPs neutronIP2 : ipList2) {
745 final String ipStr2 = neutronIP2.getIpAddress();
746 if (ipStr2.isEmpty()) {
749 programFlowsForNeutronRouterInterfacePair(node, dpid, dstNeutronRouterInterface,
750 srcNeutronRouterInterface,
751 sourceNetwork, sourceSegmentationId,
752 macAddress2, ipStr2, mask2, actionForNode,
753 false /*isReflexsive*/);
758 private void programRouterInterfaceStage1(Node node, Long dpid, String sourceSegmentationId,
759 String destinationSegmentationId,
760 String macAddress, String ipStr, int mask,
761 Action actionForNode) {
762 // Based on the local cache, figure out whether programming needs to occur. To do this, we
763 // will look at desired action for node.
765 final String cacheKey = node.getNodeId().getValue() + ":" +
766 sourceSegmentationId + ":" + destinationSegmentationId + ":" +
767 ipStr + "/" + Integer.toString(mask);
768 final Boolean isProgrammed = routerInterfacesCache.contains(cacheKey);
770 if (actionForNode == Action.DELETE && isProgrammed == Boolean.FALSE) {
771 logger.trace("programRouterInterfaceStage1 for node {} sourceSegId {} destSegId {} mac {} ip {} mask {}" +
772 " action {} is already done",
773 node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
774 macAddress, ipStr, mask, actionForNode);
777 if (actionForNode == Action.ADD && isProgrammed == Boolean.TRUE) {
778 logger.trace("programRouterInterfaceStage1 for node {} sourceSegId {} destSegId {} mac {} ip {} mask {}" +
779 " action {} is already done",
780 node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
781 macAddress, ipStr, mask, actionForNode);
785 Status status = this.programRouterInterfaceStage2(node, dpid, sourceSegmentationId, destinationSegmentationId,
786 macAddress, ipStr, mask, actionForNode);
787 if (status.isSuccess()) {
789 if (actionForNode == Action.ADD) {
790 // TODO: multiTenantAwareRouter.addInterface(UUID.fromString(tenant), ...);
791 routerInterfacesCache.add(cacheKey);
793 // TODO: multiTenantAwareRouter.removeInterface(...);
794 routerInterfacesCache.remove(cacheKey);
799 private Status programRouterInterfaceStage2(Node node, Long dpid, String sourceSegmentationId,
800 String destinationSegmentationId,
802 String address, int mask,
803 Action actionForNode) {
806 InetAddress inetAddress = InetAddress.getByName(address);
807 status = routingProvider == null ?
808 new Status(StatusCode.SUCCESS) :
809 routingProvider.programRouterInterface(dpid, sourceSegmentationId, destinationSegmentationId,
810 macAddress, inetAddress, mask, actionForNode);
811 } catch (UnknownHostException e) {
812 status = new Status(StatusCode.BADREQUEST);
815 if (status.isSuccess()) {
816 logger.debug("ProgramRouterInterface {} for mac:{} addr:{}/{} node:{} srcTunId:{} destTunId:{} action:{}",
817 routingProvider == null ? "skipped" : "programmed",
818 macAddress, address, mask, node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
821 logger.error("ProgramRouterInterface failed for mac:{} addr:{}/{} node:{} srcTunId:{} destTunId:{} action:{} status:{}",
822 macAddress, address, mask, node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
823 actionForNode, status);
828 private boolean programStaticArpStage1(Long dpid, String segOrOfPort,
829 String macAddress, String ipStr,
831 // Based on the local cache, figure out whether programming needs to occur. To do this, we
832 // will look at desired action for node.
834 final String cacheKey = dpid + ":" + segOrOfPort + ":" + ipStr;
835 final Boolean isProgrammed = staticArpEntryCache.contains(cacheKey);
837 if (action == Action.DELETE && isProgrammed == Boolean.FALSE) {
838 logger.trace("programStaticArpStage1 dpid {} segOrOfPort {} mac {} ip {} action {} is already done",
839 dpid, segOrOfPort, macAddress, ipStr, action);
842 if (action == Action.ADD && isProgrammed == Boolean.TRUE) {
843 logger.trace("programStaticArpStage1 dpid {} segOrOfPort {} mac {} ip {} action {} is already done",
844 dpid, segOrOfPort, macAddress, ipStr, action);
848 Status status = this.programStaticArpStage2(dpid, segOrOfPort, macAddress, ipStr, action);
849 if (status.isSuccess()) {
851 if (action == Action.ADD) {
852 staticArpEntryCache.add(cacheKey);
854 staticArpEntryCache.remove(cacheKey);
861 private Status programStaticArpStage2(Long dpid,
868 InetAddress inetAddress = InetAddress.getByName(address);
869 status = arpProvider == null ?
870 new Status(StatusCode.SUCCESS) :
871 arpProvider.programStaticArpEntry(dpid, segOrOfPort,
872 macAddress, inetAddress, action);
873 } catch (UnknownHostException e) {
874 status = new Status(StatusCode.BADREQUEST);
877 if (status.isSuccess()) {
878 logger.debug("ProgramStaticArp {} for mac:{} addr:{} dpid:{} segOrOfPort:{} action:{}",
879 arpProvider == null ? "skipped" : "programmed",
880 macAddress, address, dpid, segOrOfPort, action);
882 logger.error("ProgramStaticArp failed for mac:{} addr:{} dpid:{} segOrOfPort:{} action:{} status:{}",
883 macAddress, address, dpid, segOrOfPort, action, status);
888 private boolean programInboundIpRewriteStage1(Long dpid, Long inboundOFPort, String providerSegmentationId,
889 String matchAddress, String rewriteAddress,
891 // Based on the local cache, figure out whether programming needs to occur. To do this, we
892 // will look at desired action for node.
894 final String cacheKey = dpid + ":" + inboundOFPort + ":" + providerSegmentationId + ":" + matchAddress;
895 final Boolean isProgrammed = inboundIpRewriteCache.contains(cacheKey);
897 if (action == Action.DELETE && isProgrammed == Boolean.FALSE) {
898 logger.trace("programInboundIpRewriteStage1 dpid {} OFPort {} seg {} matchAddress {} rewriteAddress {}" +
899 " action {} is already done",
900 dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action);
903 if (action == Action.ADD && isProgrammed == Boolean.TRUE) {
904 logger.trace("programInboundIpRewriteStage1 dpid {} OFPort {} seg {} matchAddress {} rewriteAddress {}" +
905 " action is already done",
906 dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action);
910 Status status = programInboundIpRewriteStage2(dpid, inboundOFPort, providerSegmentationId, matchAddress,
911 rewriteAddress, action);
912 if (status.isSuccess()) {
914 if (action == Action.ADD) {
915 inboundIpRewriteCache.add(cacheKey);
917 inboundIpRewriteCache.remove(cacheKey);
924 private Status programInboundIpRewriteStage2(Long dpid, Long inboundOFPort, String providerSegmentationId,
925 String matchAddress, String rewriteAddress,
929 InetAddress inetMatchAddress = InetAddress.getByName(matchAddress);
930 InetAddress inetRewriteAddress = InetAddress.getByName(rewriteAddress);
931 status = inboundNatProvider == null ?
932 new Status(StatusCode.SUCCESS) :
933 inboundNatProvider.programIpRewriteRule(dpid, inboundOFPort, providerSegmentationId,
934 inetMatchAddress, inetRewriteAddress,
936 } catch (UnknownHostException e) {
937 status = new Status(StatusCode.BADREQUEST);
940 if (status.isSuccess()) {
941 final boolean isSkipped = inboundNatProvider == null;
942 logger.debug("programInboundIpRewriteStage2 {} for dpid:{} ofPort:{} seg:{} match:{} rewrite:{} action:{}",
943 (isSkipped ? "skipped" : "programmed"),
944 dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action);
946 logger.error("programInboundIpRewriteStage2 failed for dpid:{} ofPort:{} seg:{} match:{} rewrite:{} action:{}" +
948 dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action,
954 private void programIpRewriteExclusionStage1(Node node, Long dpid, String providerSegmentationId, String cidr,
955 Action actionForRewriteExclusion) {
956 // Based on the local cache, figure out whether programming needs to occur. To do this, we
957 // will look at desired action for node.
959 final String cacheKey = node.getNodeId().getValue() + ":" + providerSegmentationId + ":" + cidr;
960 final Boolean isProgrammed = outboundIpRewriteExclusionCache.contains(cacheKey);
962 if (actionForRewriteExclusion == Action.DELETE && isProgrammed == Boolean.FALSE) {
963 logger.trace("programIpRewriteExclusionStage1 node {} providerId {} cidr {} action {} is already done",
964 node.getNodeId().getValue(), providerSegmentationId, cidr, actionForRewriteExclusion);
967 if (actionForRewriteExclusion == Action.ADD && isProgrammed == Boolean.TRUE) {
968 logger.trace("programIpRewriteExclusionStage1 node {} providerId {} cidr {} action {} is already done",
969 node.getNodeId().getValue(), providerSegmentationId, cidr, actionForRewriteExclusion);
973 Status status = this.programIpRewriteExclusionStage2(node, dpid, providerSegmentationId, cidr,
974 actionForRewriteExclusion);
975 if (status.isSuccess()) {
977 if (actionForRewriteExclusion == Action.ADD) {
978 outboundIpRewriteExclusionCache.add(cacheKey);
980 outboundIpRewriteExclusionCache.remove(cacheKey);
985 private Status programIpRewriteExclusionStage2(Node node, Long dpid, String providerSegmentationId, String cidr,
986 Action actionForNode) {
987 final Status status = outboundNatProvider == null ? new Status(StatusCode.SUCCESS) :
988 outboundNatProvider.programIpRewriteExclusion(dpid, providerSegmentationId, cidr, actionForNode);
990 if (status.isSuccess()) {
991 final boolean isSkipped = outboundNatProvider == null;
992 logger.debug("IpRewriteExclusion {} for cidr:{} node:{} action:{}",
993 (isSkipped ? "skipped" : "programmed"),
994 cidr, node.getNodeId().getValue(), actionForNode);
996 logger.error("IpRewriteExclusion failed for cidr:{} node:{} action:{} status:{}",
997 cidr, node.getNodeId().getValue(), actionForNode, status);
1002 private void programDefaultRouteStage1(Node node, Long dpid, String providerSegmentationId,
1003 String defaultGatewayMacAddress, String gatewayIp,
1004 Action actionForNodeDefaultRoute) {
1005 // Based on the local cache, figure out whether programming needs to occur. To do this, we
1006 // will look at desired action for node.
1008 final String cacheKey = node.getNodeId().getValue() + ":" + providerSegmentationId + ":" + gatewayIp;
1009 final Boolean isProgrammed = defaultRouteCache.contains(cacheKey);
1011 if (actionForNodeDefaultRoute == Action.DELETE && isProgrammed == Boolean.FALSE) {
1012 logger.trace("programDefaultRouteStage1 node {} providerId {} mac {} gw {} action {} is already done",
1013 node.getNodeId().getValue(), providerSegmentationId, defaultGatewayMacAddress, gatewayIp,
1014 actionForNodeDefaultRoute);
1017 if (actionForNodeDefaultRoute == Action.ADD && isProgrammed == Boolean.TRUE) {
1018 logger.trace("programDefaultRouteStage1 node {} providerId {} mac {} gw {} action {} is already done",
1019 node.getNodeId().getValue(), providerSegmentationId, defaultGatewayMacAddress, gatewayIp,
1020 actionForNodeDefaultRoute);
1024 Status status = this.programDefaultRouteStage2(node, dpid, providerSegmentationId,
1025 defaultGatewayMacAddress, gatewayIp, actionForNodeDefaultRoute);
1026 if (status.isSuccess()) {
1028 if (actionForNodeDefaultRoute == Action.ADD) {
1029 defaultRouteCache.add(cacheKey);
1031 defaultRouteCache.remove(cacheKey);
1036 private Status programDefaultRouteStage2(Node node, Long dpid, String providerSegmentationId,
1037 String defaultGatewayMacAddress,
1039 Action actionForNodeDefaultRoute) {
1040 // TODO: As of Helium, mac address for default gateway is required (bug 1705).
1041 if (defaultGatewayMacAddress == null) {
1042 logger.error("ProgramDefaultRoute mac not provided. gatewayIp:{} node:{} action:{}",
1043 gatewayIp, node.getNodeId().getValue(), actionForNodeDefaultRoute);
1044 return new Status(StatusCode.NOTIMPLEMENTED); // Bug 1705
1049 InetAddress inetAddress = InetAddress.getByName(gatewayIp);
1050 status = routingProvider == null ?
1051 new Status(StatusCode.SUCCESS) :
1052 routingProvider.programDefaultRouteEntry(dpid, providerSegmentationId,
1053 defaultGatewayMacAddress, inetAddress,
1054 actionForNodeDefaultRoute);
1055 } catch (UnknownHostException e) {
1056 status = new Status(StatusCode.BADREQUEST);
1059 if (status.isSuccess()) {
1060 logger.debug("ProgramDefaultRoute {} for mac:{} gatewayIp:{} node:{} action:{}",
1061 routingProvider == null ? "skipped" : "programmed",
1062 defaultGatewayMacAddress, gatewayIp, node.getNodeId().getValue(), actionForNodeDefaultRoute);
1064 logger.error("ProgramDefaultRoute failed for mac:{} gatewayIp:{} node:{} action:{} status:{}",
1065 defaultGatewayMacAddress, gatewayIp, node.getNodeId().getValue(), actionForNodeDefaultRoute, status);
1070 private void programFlowsForFloatingIP(final NeutronFloatingIP neutronFloatingIP, Boolean isDelete) {
1071 Preconditions.checkNotNull(neutronFloatingIP);
1073 final String networkUUID = neutronFloatingIP.getFloatingNetworkUUID();
1074 final String routerMacAddress = networkIdToRouterMacCache.get(networkUUID);
1076 // If there is no router interface handling the networkUUID, we are done
1077 if (routerMacAddress == null || routerMacAddress.isEmpty()) {
1081 final NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(networkUUID);
1082 final String providerSegmentationId = neutronNetwork != null ?
1083 neutronNetwork.getProviderSegmentationID() : null;
1084 final String fixedIPAddress = neutronFloatingIP.getFixedIPAddress();
1085 final String floatingIpAddress = neutronFloatingIP.getFloatingIPAddress();
1087 if (providerSegmentationId == null || providerSegmentationId.isEmpty() ||
1088 // routerMacAddress == null || routerMacAddress.isEmpty() ||
1089 fixedIPAddress == null || fixedIPAddress.isEmpty() ||
1090 floatingIpAddress == null || floatingIpAddress.isEmpty()) {
1091 return; // done: go no further w/out all the info needed...
1094 final Action action = isDelete ? Action.DELETE : Action.ADD;
1095 List<Node> nodes = nodeCacheManager.getBridgeNodes();
1096 if (nodes.isEmpty()) {
1097 logger.trace("programFlowsForFloatingIP has no nodes to work with");
1099 for (Node node : nodes) {
1100 final Long dpid = getDpidForIntegrationBridge(node);
1105 final Action actionForNode =
1106 tenantNetworkManager.isTenantNetworkPresentInNode(node, providerSegmentationId) ?
1107 action : Action.DELETE;
1109 // Rewrite from float to fixed and vice-versa
1110 programIpRewriteStage1(node, dpid, providerSegmentationId, fixedIPAddress, floatingIpAddress, actionForNode);
1114 private void programIpRewriteStage1(Node node, Long dpid, String providerSegmentationId,
1115 String matchAddress, String rewriteAddress,
1116 Action actionForNode) {
1117 // Based on the local cache, figure out whether programming needs to occur. To do this, we
1118 // will look at desired action for node.
1120 final String cacheKey = node.getNodeId().getValue() + ":" + providerSegmentationId + ":" +
1121 matchAddress + ":" + rewriteAddress;
1122 final Boolean isProgrammed = outboundIpRewriteCache.contains(cacheKey);
1124 if (actionForNode == Action.DELETE && isProgrammed == Boolean.FALSE) {
1125 logger.trace("programIpRewriteStage1 node {} providerId {} matchAddr {} rewriteAddr {} action {}" +
1127 node.getNodeId().getValue(), providerSegmentationId, matchAddress, rewriteAddress,
1131 if (actionForNode == Action.ADD && isProgrammed == Boolean.TRUE) {
1132 logger.trace("programIpRewriteStage1 node {} providerId {} matchAddr {} rewriteAddr {} action {}" +
1134 node.getNodeId().getValue(), providerSegmentationId, matchAddress, rewriteAddress,
1139 Status status = this.programIpRewriteStage2(node, dpid, providerSegmentationId, matchAddress, rewriteAddress,
1141 if (status.isSuccess()) {
1143 if (actionForNode == Action.ADD) {
1144 outboundIpRewriteCache.add(cacheKey);
1146 outboundIpRewriteCache.remove(cacheKey);
1151 private Status programIpRewriteStage2(Node node, Long dpid, String providerSegmentationId,
1152 String matchAddress, String rewriteAddress,
1153 Action actionForNode) {
1156 InetAddress inetMatchAddress = InetAddress.getByName(matchAddress);
1157 InetAddress inetRewriteAddress = InetAddress.getByName(rewriteAddress);
1158 status = outboundNatProvider == null ?
1159 new Status(StatusCode.SUCCESS) :
1160 outboundNatProvider.programIpRewriteRule(dpid, providerSegmentationId,
1161 inetMatchAddress, inetRewriteAddress, actionForNode);
1162 } catch (UnknownHostException e) {
1163 status = new Status(StatusCode.BADREQUEST);
1166 if (status.isSuccess()) {
1167 final boolean isSkipped = outboundNatProvider == null;
1168 logger.debug("ProgramIpRewrite {} for match:{} rewrite:{} node:{} action:{}",
1169 (isSkipped ? "skipped" : "programmed"),
1170 matchAddress, rewriteAddress, node.getNodeId().getValue(), actionForNode);
1172 logger.error("ProgramIpRewrite failed for match:{} rewrite:{} node:{} action:{} status:{}",
1173 matchAddress, rewriteAddress, node.getNodeId().getValue(), actionForNode, status);
1178 private int getMaskLenFromCidr(String cidr) {
1179 if (cidr == null) return 0;
1180 String[] splits = cidr.split("/");
1181 if (splits.length != 2) return 0;
1185 result = Integer.parseInt(splits[1].trim());
1187 catch (NumberFormatException nfe)
1194 private Long getDpidForIntegrationBridge(Node node) {
1195 // Check if node is integration bridge; and only then return its dpid
1196 if (southbound.getBridge(node, configurationService.getIntegrationBridgeName()) != null) {
1197 return southbound.getDataPathId(node);
1203 * Return String that represents OF port with marker explicitly provided (reverse of MatchUtils:parseExplicitOFPort)
1205 * @param ofPort the OF port number
1206 * @return the string with encoded OF port (example format "OFPort|999")
1208 public static String encodeExcplicitOFPort(Long ofPort) {
1209 return "OFPort|" + ofPort.toString();
1213 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
1214 tenantNetworkManager =
1215 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
1216 configurationService =
1217 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
1219 (ArpProvider) ServiceHelper.getGlobalInstance(ArpProvider.class, this);
1220 inboundNatProvider =
1221 (InboundNatProvider) ServiceHelper.getGlobalInstance(InboundNatProvider.class, this);
1222 outboundNatProvider =
1223 (OutboundNatProvider) ServiceHelper.getGlobalInstance(OutboundNatProvider.class, this);
1225 (RoutingProvider) ServiceHelper.getGlobalInstance(RoutingProvider.class, this);
1226 l3ForwardingProvider =
1227 (L3ForwardingProvider) ServiceHelper.getGlobalInstance(L3ForwardingProvider.class, this);
1229 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
1231 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
1233 initL3AdapterMembers();
1237 public void setDependencies(Object impl) {
1238 if (impl instanceof INeutronNetworkCRUD) {
1239 neutronNetworkCache = (INeutronNetworkCRUD)impl;
1240 } else if (impl instanceof INeutronPortCRUD) {
1241 neutronPortCache = (INeutronPortCRUD)impl;
1242 } else if (impl instanceof INeutronSubnetCRUD) {
1243 neutronSubnetCache = (INeutronSubnetCRUD)impl;
1244 } else if (impl instanceof ArpProvider) {
1245 arpProvider = (ArpProvider)impl;
1246 } else if (impl instanceof InboundNatProvider) {
1247 inboundNatProvider = (InboundNatProvider)impl;
1248 } else if (impl instanceof OutboundNatProvider) {
1249 outboundNatProvider = (OutboundNatProvider)impl;
1250 } else if (impl instanceof RoutingProvider) {
1251 routingProvider = (RoutingProvider)impl;
1252 } else if (impl instanceof L3ForwardingProvider) {
1253 l3ForwardingProvider = (L3ForwardingProvider)impl;