diff --git a/nvmet/nvme.py b/nvmet/nvme.py
index b5e6e4f661d5be20e1fd052e7c2be80699844b4e..f8b1ee97527ec591165ad03b6835f357de2f2f2e 100644
--- a/nvmet/nvme.py
+++ b/nvmet/nvme.py
@@ -659,8 +659,18 @@ class Port(CFSNode):
         self._check_self()
         for s in self.subsystems:
             self.remove_subsystem(s)
+        for r in self.referrals:
+            r.delete()
         super(Port, self).delete()
 
+    def _list_referrals(self):
+        self._check_self()
+        for d in os.listdir("%s/referrals/" % self._path):
+            yield Referral(self, d, 'lookup')
+
+    referrals = property(_list_referrals,
+                         doc="Get the list of Referrals for this Port.")
+
     @classmethod
     def setup(cls, root, n, err_func):
         '''
@@ -682,11 +692,65 @@ class Port(CFSNode):
         port._setup_attrs(n, err_func)
         for s in n.get('subsystems', []):
             port.add_subsystem(s)
+        for r in n.get('referrals', []):
+            Referral.setup(port, r, err_func)
 
     def dump(self):
         d = super(Port, self).dump()
         d['portid'] = self.portid
         d['subsystems'] = self.subsystems
+        d['referrals'] = [r.dump() for r in self.referrals]
+        return d
+
+
+class Referral(CFSNode):
+    '''
+    This is an interface to a NVMe Referral in configFS.
+    '''
+
+    def __repr__(self):
+        return "<Referral %d>" % self.name
+
+    def __init__(self, port, name, mode='any'):
+        super(Referral, self).__init__()
+
+        if not isinstance(port, Port):
+            raise CFSError("Invalid parent class")
+
+        self.attr_groups = ['addr']
+        self.port = port
+        self._name = name
+        self._path = "%s/referrals/%s" % (self.port.path, self._name)
+        self._create_in_cfs(mode)
+
+    def _get_name(self):
+        return self._name
+
+    name = property(_get_name, doc="Get the Referral name.")
+
+    @classmethod
+    def setup(cls, port, n, err_func):
+        '''
+        Set up a Referral based upon n dict, from saved config.
+        Guard against missing or bad dict items, but keep going.
+        Call 'err_func' for each error.
+        '''
+
+        if 'name' not in n:
+            err_func("'name' not defined for Referral")
+            return
+
+        try:
+            r = Referral(port, n['name'])
+        except CFSError as e:
+            err_func("Could not create Referral object: %s" % e)
+            return
+
+        r._setup_attrs(n, err_func)
+
+    def dump(self):
+        d = super(Referral, self).dump()
+        d['name'] = self.name
         return d
 
 
diff --git a/nvmet/test_nvmet.py b/nvmet/test_nvmet.py
index 38de70db9c94b7afc42c9986c9b0e7667a72c53a..445050cc4fe6f84bfffacbbc577956602c1fd5de 100644
--- a/nvmet/test_nvmet.py
+++ b/nvmet/test_nvmet.py
@@ -283,6 +283,89 @@ class TestNvmet(unittest.TestCase):
             h.delete()
         self.assertEqual(len(list(root.hosts)), 0)
 
+    def test_referral(self):
+        root = nvme.Root()
+        root.clear_existing()
+
+        # create port
+        p = nvme.Port(root, mode='create')
+        self.assertEqual(len(list(p.referrals)), 0)
+
+        # create mode
+        r1 = nvme.Referral(p, name="1", mode='create')
+        self.assertIsNotNone(r1)
+        self.assertEqual(len(list(p.referrals)), 1)
+
+        # any mode, should create
+        r2 = nvme.Referral(p, name="2", mode='any')
+        self.assertIsNotNone(r2)
+        self.assertEqual(len(list(p.referrals)), 2)
+
+        # duplicate
+        self.assertRaises(nvme.CFSError, nvme.Referral,
+                          p, name="2", mode='create')
+        self.assertEqual(len(list(p.referrals)), 2)
+
+        # lookup using any, should not create
+        r = nvme.Referral(p, name="1", mode='any')
+        self.assertEqual(r1, r)
+        self.assertEqual(len(list(p.referrals)), 2)
+
+        # lookup only
+        r = nvme.Referral(p, name="2", mode='lookup')
+        self.assertEqual(r2, r)
+        self.assertEqual(len(list(p.referrals)), 2)
+
+        # non-existant lookup
+        self.assertRaises(nvme.CFSError, nvme.Referral, p, name="foo",
+                          mode='lookup')
+
+        # basic state
+        self.assertTrue('addr' in r.attr_groups)
+        self.assertFalse(r.get_enable())
+
+        # now set trtype to loop and other attrs and enable
+        r.set_attr('addr', 'trtype', 'loop')
+        r.set_attr('addr', 'adrfam', 'ipv4')
+        r.set_attr('addr', 'traddr', '192.168.0.1')
+        r.set_attr('addr', 'treq', 'not required')
+        r.set_attr('addr', 'trsvcid', '1023')
+        r.set_enable(1)
+
+        # test double enable
+        r.set_enable(1)
+
+        # test that we can't write to attrs while enabled
+        self.assertRaises(nvme.CFSError, r.set_attr, 'addr', 'trtype',
+                          'rdma')
+        self.assertRaises(nvme.CFSError, r.set_attr, 'addr', 'adrfam',
+                          'ipv6')
+        self.assertRaises(nvme.CFSError, r.set_attr, 'addr', 'traddr',
+                          '10.0.0.1')
+        self.assertRaises(nvme.CFSError, r.set_attr, 'addr', 'treq',
+                          'required')
+        self.assertRaises(nvme.CFSError, r.set_attr, 'addr', 'trsvcid',
+                          '21')
+
+        # disable: once and twice
+        r.set_enable(0)
+        r.set_enable(0)
+
+        # check that the attrs haven't been tampered with
+        self.assertEqual(r.get_attr('addr', 'trtype'), 'loop')
+        self.assertEqual(r.get_attr('addr', 'adrfam'), 'ipv4')
+        self.assertEqual(r.get_attr('addr', 'traddr'), '192.168.0.1')
+        self.assertEqual(r.get_attr('addr', 'treq'), 'not required')
+        self.assertEqual(r.get_attr('addr', 'trsvcid'), '1023')
+
+        # enable again, and try to remove while enabled
+        r.set_enable(1)
+        r.delete()
+
+        # remove the other one while disabled:
+        r1.delete()
+        self.assertEqual(len(list(p.referrals)), 0)
+
     def test_allowed_hosts(self):
         root = nvme.Root()
 
diff --git a/nvmetcli b/nvmetcli
index 35c5e676e4e0c5e8f6358f2d5f8723320376be7c..58c8d27ba35a4ccdf9869aa142874a478a1cf1f2 100755
--- a/nvmetcli
+++ b/nvmetcli
@@ -340,6 +340,7 @@ class UIPortNode(UINode):
     def __init__(self, parent, cfnode):
         UINode.__init__(self, str(cfnode.portid), parent, cfnode)
         UIPortSubsystemsNode(self)
+        UIReferralsNode(self)
 
     def status(self):
         if self.cfnode.get_enable():
@@ -408,6 +409,85 @@ class UIPortSubsystemNode(UINode):
         UINode.__init__(self, nqn, parent)
 
 
+class UIReferralsNode(UINode):
+    def __init__(self, parent):
+        UINode.__init__(self, 'referrals', parent)
+
+    def refresh(self):
+        self._children = set([])
+        for r in self.parent.cfnode.referrals:
+            UIReferralNode(self, r)
+
+    def ui_command_create(self, name):
+        '''
+        Creates a new referral.
+
+        SEE ALSO
+        ========
+        B{delete}
+        '''
+        r = nvme.Referral(self.parent.cfnode, name, mode='create')
+        UIReferralNode(self, r)
+
+    def ui_command_delete(self, name):
+        '''
+        Deletes the referral with the specified I{name}.
+
+        SEE ALSO
+        ========
+        B{create}
+        '''
+        r = nvme.Referral(self.parent.cfnode, name, mode='lookup')
+        r.delete()
+        self.refresh()
+
+
+class UIReferralNode(UINode):
+    def __init__(self, parent, cfnode):
+        UINode.__init__(self, cfnode.name, parent, cfnode)
+
+    def status(self):
+        if self.cfnode.get_enable():
+            return "enabled"
+        return "disabled"
+
+    def ui_command_enable(self):
+        '''
+        Enables the current Referral.
+
+        SEE ALSO
+        ========
+        B{disable}
+        '''
+        if self.cfnode.get_enable():
+            self.shell.log.info("The Referral is already enabled.")
+        else:
+            try:
+                self.cfnode.set_enable(1)
+                self.shell.log.info("The Referral has been enabled.")
+            except Exception as e:
+                raise configshell.ExecutionError(
+                    "The Referral could not be enabled.")
+
+    def ui_command_disable(self):
+        '''
+        Disables the current Referral.
+
+        SEE ALSO
+        ========
+        B{enable}
+        '''
+        if not self.cfnode.get_enable():
+            self.shell.log.info("The Referral is already disabled.")
+        else:
+            try:
+                self.cfnode.set_enable(0)
+                self.shell.log.info("The Referral has been disabled.")
+            except Exception as e:
+                raise configshell.ExecutionError(
+                    "The Referral could not be disabled.")
+
+
 class UIHostsNode(UINode):
     def __init__(self, parent):
         UINode.__init__(self, 'hosts', parent)