def supportedEncaps(self): if self.useGRE: yield Encapsulation(Encapsulation.GRE) yield Encapsulation(Encapsulation.DEFAULT) # we will accept routes with no encap # specified and force the use of GRE else: yield Encapsulation(Encapsulation.MPLS) if self.vxlanEncap: yield Encapsulation(Encapsulation.VXLAN)
def _checkEncaps(self, route): ''' returns a list of encaps supported by both the dataplane driver and the advertized route (based on BGP Encapsulation community) logs a warning if there is no common encap ''' advEncaps = None try: advEncaps = filter( lambda ecom: isinstance(ecom, Encapsulation), route.attributes[AttributeID.EXTENDED_COMMUNITY].communities) self.log.debug("Advertized Encaps: %s", advEncaps) except KeyError: self.log.debug("no encap advertized, let's use default") if not advEncaps: advEncaps = [Encapsulation(Encapsulation.DEFAULT)] goodEncaps = set(advEncaps) & set( self.dataplaneDriver.supportedEncaps()) if not goodEncaps: self.log.warning( "No encap supported by dataplane driver for route" " %s, advertized: %s, dataplane supports: {%s}", route, advEncaps, ", ".join([ repr(encap) for encap in self.dataplaneDriver.supportedEncaps() ])) return goodEncaps
class DummyDataplaneDriver(_DummyDataplaneDriver): dataplaneInstanceClass = DummyVPNInstanceDataplane encaps = [Encapsulation(Encapsulation.VXLAN)] def __init__(self, *args): _DummyDataplaneDriver.__init__(self, *args)
def setupDataplaneForRemoteEndpoint(self, prefix, remotePE, label, nlri, encaps): dec_ttl_action = "" if IPNetwork(repr(prefix)) not in IPNetwork("%s/%s" % (self.gatewayIP, self.mask)): dec_ttl_action = "dec_ttl" label_action = "push_mpls:0x8847,load:%s->OXM_OF_MPLS_LABEL[]" % label # Check if prefix is from a local VRF if self.driver.getLocalAddress() == str(remotePE): self.log.debug("Local route, using a resubmit action") # For local traffic, we have to use a resubmit action output_action = "resubmit:%s" % self._mplsInPort() else: if (self.driver.vxlanEncap and Encapsulation(Encapsulation.VXLAN) in encaps): self.log.debug("Will use a VXLAN encap for this destination") output_action = "set_field:%s->tun_dst,output:%s" % ( str(remotePE), self.driver.ovsVXLANTunnelPortNumber) label_action = "set_field:%d->tunnel_id" % label # OR set_field:0xfoo->tun_id ? elif self.driver.useGRE: self.log.debug("Using MPLS/GRE encap") output_action = "set_field:%s->tun_dst,output:%s" % ( str(remotePE), self.driver.ovsGRETunnelPortNumber) else: self.log.debug("Using bare MPLS encap") # Find remote router MAC address try: remotePE_mac_address = self._find_remote_mac_address( remotePE) self.log.debug("MAC address found for remote router " "%(remotePE)s: %(remotePE_mac_address)s", locals()) except exc.RemotePEMACAddressNotFound as e: self.log.error("An error occured during setupDataplaneFor" "RemoteEndpoint: %s", e) # Map traffic to remote IP address as MPLS on ethX to remote # router MAC address output_action = "mod_dl_src:%s,mod_dl_dst:%s,output:%s" % ( self.mplsIfMacAddress, remotePE_mac_address, self.driver.ovsMplsIfPortNumber) # Check if prefix is a default route nw_dst_match = "" if IPNetwork(repr(prefix)).prefixlen != 0: nw_dst_match = ',nw_dst=%s' % prefix self._ovs_flow_add( 'ip,in_port=%s%s' % (self.patchPortInNumber, nw_dst_match), ','.join(filter(None, (dec_ttl_action, label_action, output_action))), self.driver.ovs_table_vrfs)
def _genExtendedCommunities(self): ecommunities = ECommunities(copy(self.exportRTs)) for encap in self.dataplaneDriver.supportedEncaps(): if not isinstance(encap, Encapsulation): raise Exception("dataplaneDriver.supportedEncaps() should " "return a list of Encapsulation objects") if encap != Encapsulation(Encapsulation.DEFAULT): ecommunities.add(encap) # FIXME: si DEFAULT + xxx => adv MPLS return ecommunities
class LinuxVXLANDataplaneDriver(DataplaneDriver): """ E-VPN Dataplane driver relying on the Linux kernel linuxbridge VXLAN implementation. """ dataplaneInstanceClass = LinuxVXLANEVIDataplane requiredKernel = "3.11.0" encaps = [Encapsulation(Encapsulation.VXLAN)] def __init__(self, config, init=True): LookingGlassLocalLogger.__init__(self, __name__) self.log.info("Initializing %s", self.__class__.__name__) try: self.vxlanDestPort = int(config.get("vxlan_dst_port", 0)) or None except ValueError: raise Exception("Could not parse specified vxlan_dst_port: %s" % config["vxlan_dst_port"]) DataplaneDriver.__init__(self, config, init) def _initReal(self, config): self.config = config self.log.info("Really initializing %s", self.__class__.__name__) o = self._runCommand("uname -r") kernelRelease = o[0][0].split("-")[0] if (StrictVersion(kernelRelease) < StrictVersion(LinuxVXLANDataplaneDriver.requiredKernel)): self.log.warning("%s requires at least Linux kernel %s (you are" " running %s)" % (self.__class__.__name__, LinuxVXLANDataplaneDriver.requiredKernel, kernelRelease)) self._runCommand("modprobe vxlan") def resetState(self): self.log.debug("Resetting %s dataplane", self.__class__.__name__) # delete all EVPN bridges cmd = "brctl show | tail -n +2 | awk '{print $1}'| grep '%s'" for bridge in self._runCommand(cmd % BRIDGE_NAME_PREFIX, raiseExceptionOnError=False, acceptableReturnCodes=[0, 1])[0]: self._runCommand("ip link set %s down" % bridge) self._runCommand("brctl delbr %s" % bridge) # delete all VXLAN interfaces cmd = "ip link show | awk '{print $2}' | tr -d ':' | grep '%s'" for interface in self._runCommand(cmd % VXLAN_INTERFACE_PREFIX, raiseExceptionOnError=False, acceptableReturnCodes=[0, 1])[0]: self._runCommand("ip link set %s down" % interface) self._runCommand("ip link delete %s" % interface) def _cleanupReal(self): # FIXME: need to refine what would be different self.resetState() def _runCommand(self, command, *args, **kwargs): return runCommand(self.log, command, *args, **kwargs)
class DataplaneDriver(LookingGlassLocalLogger): __metaclass__ = ABCMeta dataplaneInstanceClass = None encaps = [Encapsulation(Encapsulation.DEFAULT)] makeB4BreakSupport = False ecmpSupport = False @logDecorator.log def __init__(self, config, init=True): '''config is a dict''' LookingGlassLocalLogger.__init__(self) assert(issubclass(self.dataplaneInstanceClass, VPNInstanceDataplane)) self.config = config self.local_address = None try: self.local_address = self.config["dataplane_local_address"] socket.inet_pton(socket.AF_INET, self.local_address) self.log.info("Will use %s as local_address", self.local_address) except KeyError: self.log.info("Will use BGP address as dataplane_local_address") self.local_address = None except socket.error: raise Exception("malformed local_address: '%s'" % self.local_address) # skipped if instantiated with init=False, to be used for cleanup if init: self._initReal(config) # Flag to trigger cleanup all dataplane states on first call to # vifPlugged self.firstInit = True @abstractmethod def resetState(self): pass @abstractmethod def _initReal(self, config): ''' This is called after resetState (which, e.g. cleans up the stuff possibly left-out by a previous failed run). All init things that should not be cleaned up go here. ''' pass @logDecorator.logInfo def initializeDataplaneInstance(self, instanceId, externalInstanceId, gatewayIP, mask, instanceLabel, **kwargs): ''' returns a VPNInstanceDataplane subclass after calling resetState on the dataplane driver, if this is the first call to initializeDataplaneInstance ''' if self.firstInit: self.log.info("First VPN instance init, resetting dataplane state") try: self.resetState() except Exception as e: self.log.error("Exception while resetting state: %s", e) self.firstInit = False else: self.log.debug("(not resetting dataplane state)") return self.dataplaneInstanceClass(self, instanceId, externalInstanceId, gatewayIP, mask, instanceLabel, **kwargs) def cleanup(self): # FIXME: to be clarified: can be removed ? should call resetState ? self._cleanupReal() def getLocalAddress(self): return self.local_address def supportedEncaps(self): return self.__class__.encaps def _runCommand(self, command, *args, **kwargs): return runCommand(self.log, command, *args, **kwargs) def getLGMap(self): encaps = [] for encap in self.supportedEncaps(): encaps.append(repr(encap)) return { "name": (LGMap.VALUE, self.__class__.__name__), "local_address": (LGMap.VALUE, self.local_address), "supported_encaps": (LGMap.VALUE, encaps), "config": (LGMap.VALUE, self.config) }