Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
class DummyDataplaneDriver(_DummyDataplaneDriver):

    dataplaneInstanceClass = DummyVPNInstanceDataplane
    encaps = [Encapsulation(Encapsulation.VXLAN)]

    def __init__(self, *args):
        _DummyDataplaneDriver.__init__(self, *args)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
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)
        }