diff --git a/blivet/devicelibs/mdraid.py b/blivet/devicelibs/mdraid.py
index 9c827e1..c69ce90 100644
--- a/blivet/devicelibs/mdraid.py
+++ b/blivet/devicelibs/mdraid.py
@@ -35,72 +35,176 @@ log = logging.getLogger("blivet")
 MD_SUPERBLOCK_SIZE = 2.0    # MB
 MD_CHUNK_SIZE = 0.5         # MB
 
-# raidlevels constants
-RAID10 = 10
-RAID6 = 6
-RAID5 = 5
-RAID4 = 4
-RAID1 = 1
-RAID0 = 0
-
-raid_levels = [ RAID0, RAID1, RAID4, RAID5, RAID6, RAID10 ]
-
-raid_descriptors = {RAID10: ("raid10", "RAID10", "10", 10),
-                    RAID6: ("raid6", "RAID6", "6", 6),
-                    RAID5: ("raid5", "RAID5", "5", 5),
-                    RAID4: ("raid4", "RAID4", "4", 4),
-                    RAID1: ("raid1", "mirror", "RAID1", "1", 1),
-                    RAID0: ("raid0", "stripe", "RAID0", "0", 0)}
-
-def raidLevel(descriptor):
-    for level in raid_levels:
-        if isRaid(level, descriptor):
-            return level
-    else:
-        raise MDRaidError("invalid raid level descriptor %s" % descriptor)
+raid_levels = []
 
-def raidLevelString(level):
-    if level in raid_descriptors.keys():
-        return raid_descriptors[level][0]
-    else:
-        raise MDRaidError("invalid raid level constant %s" % level)
+class RAIDLevel(object):
+    name = None
+    min_members = 2
+    module_name = None
+    create_bitmap = True
+
+    def get_max_spares(self, member_count):
+        return member_count - self.min_members
+
+    def get_member_size(self, size, member_count):
+        """ Return member device size given array size and member count.
+
+            This is intended as an estimate for calculations related to
+            creation of a new array.
+        """
+        if member_count < self.min_members:
+            raise MDRaidError("raid%d requires at least %d disks"
+                             % (self.name, self.min_members))
+
+        space = self.get_base_member_size(size, member_count)
+        space += MD_SUPERBLOCK_SIZE
+        return space
+
+    def get_base_member_size(self, size, member_count):
+        raise NotImplementedError()
+
+    @classmethod
+    def get_module_name(cls):
+        name = cls.name
+        if cls.module_name:
+            name = cls.module_name
+
+        return name
+
+    @property
+    def module_name(self):
+        return self.__class__.get_module_name()
+
+    @classmethod
+    def get_availability(cls):
+        available = False
+        if os.access(MDSTAT_PATH, os.R_OK):
+            lines = open(MDSTAT_PATH).readlines()
+            for line in lines:
+                if not line.startswith("Personalities:"):
+                    continue
+
+                for level in line.split():
+                    level = level[1:-1]     # strip off enclosing brackets
+                    if level.lower() == self.name:
+                        available = True
+                        break
+
+        return available
+
+    @property
+    def available(self):
+        return self.__class__.get_availability()
+
+    def __call__(self):
+        return self
+
+    ##
+    ## Methods to allow comparison with raid level strings
+    ##
+    def __str__(self):
+        return self.name
+
+    def __eq__(self, other):
+        return str(self) == str(other).lower()
+
+class RAID0(RAIDLevel):
+    name = "raid0"
+    # bitmaps are not meaningful on raid0 according to mdadm-3.0.3
+    create_bitmap = False
+
+    def get_base_member_size(self, size, member_count):
+        # you need the sum of the member sizes to equal your desired capacity
+        return size / member_count
 
-def isRaid(raid, raidlevel):
-    """Return whether raidlevel is a valid descriptor of raid"""
-    if raid in raid_descriptors:
-        return raidlevel in raid_descriptors[raid]
-    else:
-        raise MDRaidError("invalid raid level %d" % raid)
-
-def get_raid_min_members(raidlevel):
-    """Return the minimum number of raid members required for raid level"""
-    raid_min_members = {RAID10: 4,
-                        RAID6: 4,
-                        RAID5: 3,
-                        RAID4: 3,
-                        RAID1: 2,
-                        RAID0: 2}
-
-    for raid, min_members in raid_min_members.items():
-        if isRaid(raid, raidlevel):
-            return min_members
-
-    raise MDRaidError("invalid raid level %d" % raidlevel)
-
-def get_raid_max_spares(raidlevel, nummembers):
-    """Return the maximum number of raid spares for raidlevel."""
-    raid_max_spares = {RAID10: lambda: max(0, nummembers - get_raid_min_members(RAID10)),
-                       RAID6: lambda: max(0, nummembers - get_raid_min_members(RAID6)),
-                       RAID5: lambda: max(0, nummembers - get_raid_min_members(RAID5)),
-                       RAID4: lambda: max(0, nummembers - get_raid_min_members(RAID4)),
-                       RAID1: lambda: max(0, nummembers - get_raid_min_members(RAID1)),
-                       RAID0: lambda: 0}
-
-    for raid, max_spares_func in raid_max_spares.items():
-        if isRaid(raid, raidlevel):
-            return max_spares_func()
-
-    raise MDRaidError("invalid raid level %d" % raidlevel)
+RAID0 = RAID0()
+raid_levels.append(RAID0)
+
+class RAID1(RAIDLevel):
+    name = "raid1"
+
+    def get_base_member_size(self, size, member_count):
+         # you need each member's size to equal your desired capacity
+        return size
+
+RAID1 = RAID1()
+raid_levels.append(RAID1)
+
+class RAID4(RAIDLevel):
+    name = "raid4"
+    module_name = "raid456"
+    min_members = 3
+
+    def get_base_member_size(self, size, member_count):
+        # you need the sum of all but one members' sizes to equal your desired
+        # capacity
+        return size / (member_count - 1)
+
+RAID4 = RAID4()
+raid_levels.append(RAID4)
+
+class RAID5(RAIDLevel):
+    name = "raid5"
+    module_name = "raid456"
+    min_members = 3
+
+    def get_base_member_size(self, size, member_count):
+         # you need the sum of all but one members' sizes to equal your desired
+         # capacity
+        return size / (member_count - 1)
+
+RAID5 = RAID5()
+raid_levels.append(RAID5)
+
+class RAID6(RAIDLevel):
+    name = "raid6"
+    module_name = "raid456"
+    min_members = 4
+
+    def get_base_member_size(self, size, member_count):
+         # you need the sum of all but two members' sizes to equal your desired
+         # capacity
+        return size / (member_count - 2)
+
+RAID6 = RAID6()
+raid_levels.append(RAID6)
+
+class RAID10(RAIDLevel):
+    name = "raid10"
+
+    def get_base_member_size(self, size, member_count):
+         # you need the sum of the member sizes to equal twice your desired
+         # capacity
+        return size / (disks / 2.0)
+
+RAID10 = RAID10()
+raid_levels.append(RAID10)
+
+class LINEAR(RAIDLevel):
+    name = "linear"
+
+    def get_base_member_size(self, size, member_count):
+        # XXX This doesn't really apply to linear
+        return size / member_count
+
+LINEAR = LINEAR()
+raid_levels.append(LINEAR)
+
+class CONTAINER(RAIDLevel):
+    name = "container"
+    min_members = 1
+
+    def get_base_member_size(self, size, member_count):
+        # XXX This doesn't really apply to container
+        return size / member_count
+
+CONTAINER = CONTAINER()
+raid_levels.append(CONTAINER)
+
+def get_member_space(size, disks, level=None):
+    """ Return the combined size of all member devices. """
+    level_class = raid_level_factory(level)
+    return level_class.get_member_size(size, disks) * disks
 
 def get_raid_superblock_size(size, version=None):
     """ mdadm has different amounts of space reserved for its use depending
@@ -126,40 +230,6 @@ def get_raid_superblock_size(size, version=None):
     log.info("Using %sMB superBlockSize" % (headroom))
     return headroom
 
-def get_member_space(size, disks, level=None):
-    space = 0   # size of *each* member device
-
-    if isinstance(level, str):
-        level = raidLevel(level)
-
-    min_members = get_raid_min_members(level)
-    if disks < min_members:
-        raise MDRaidError("raid%d requires at least %d disks"
-                         % (level, min_members))
-
-    if level == RAID0:
-        # you need the sum of the member sizes to equal your desired capacity
-        space = size / disks
-    elif level == RAID1:
-        # you need each member's size to equal your desired capacity
-        space = size
-    elif level in (RAID4, RAID5):
-        # you need the sum of all but one members' sizes to equal your desired
-        # capacity
-        space = size / (disks - 1)
-    elif level == RAID6:
-        # you need the sum of all but two members' sizes to equal your desired
-        # capacity
-        space = size / (disks - 2)
-    elif level == RAID10:
-        # you need the sum of the member sizes to equal twice your desired
-        # capacity
-        space = size / (disks / 2.0)
-
-    space += get_raid_superblock_size(size)
-
-    return space * disks
-
 def mdadm(args):
     ret = util.run_program(["mdadm"] + args)
     if ret:
diff --git a/blivet/devices.py b/blivet/devices.py
index 39d96c1..e09eadc 100644
--- a/blivet/devices.py
+++ b/blivet/devices.py
@@ -2964,7 +2964,7 @@ class MDRaidArrayDevice(StorageDevice):
 
             Keyword Arguments:
 
-                level -- the device's RAID level (a string, eg: '1' or 'raid1')
+                level -- the device's RAID level (a string, eg: 'raid1')
                 metadataVersion -- the version of the device's md metadata
                 parents -- list of member devices (StorageDevice instances)
                 size -- the device's size (units/format TBD)
@@ -3119,10 +3119,10 @@ class MDRaidArrayDevice(StorageDevice):
             elif self.level == mdraid.RAID10:
                 size = (self.memberDevices / 2.0) * smallestMemberSize
                 size -= size % self.chunkSize
-            log.debug("non-existent RAID %s size == %s" % (self.level, size))
+            log.debug("non-existent MD %s size == %s" % (self.level, size))
         else:
             size = self.partedDevice.getSize()
-            log.debug("existing RAID %s size == %s" % (self.level, size))
+            log.debug("existing MD %s size == %s" % (self.level, size))
 
         return size
 
@@ -3133,7 +3133,7 @@ class MDRaidArrayDevice(StorageDevice):
         elif self.level == mdraid.RAID1:
             levelstr = "mirror"
         else:
-            levelstr = "raid%s" % self.level
+            levelstr = self.level
 
         if self.type == "mdcontainer":
             return "BIOS RAID container"
@@ -3157,7 +3157,7 @@ class MDRaidArrayDevice(StorageDevice):
     @property
     def dict(self):
         d = super(MDRaidArrayDevice, self).dict
-        d.update({"level": self.level,
+        d.update({"level": str(self.level),
                   "spares": self.spares, "memberDevices": self.memberDevices,
                   "totalDevices": self.totalDevices,
                   "metadataVersion": self.metadataVersion})
@@ -3174,7 +3174,7 @@ class MDRaidArrayDevice(StorageDevice):
             fmt = "ARRAY %s UUID=%s\n"
             return fmt % (self.path, self.uuid)
 
-        fmt = "ARRAY %s level=raid%d num-devices=%d UUID=%s\n"
+        fmt = "ARRAY %s level=%s num-devices=%d UUID=%s\n"
         return fmt % (self.path, self.level, self.memberDevices, self.uuid)
 
     @property
