diff --git a/lib/ansible/modules/network/nxos/nxos_pim_interface.py b/lib/ansible/modules/network/nxos/nxos_pim_interface.py
new file mode 100644
index 00000000000..42413f537de
--- /dev/null
+++ b/lib/ansible/modules/network/nxos/nxos_pim_interface.py
@@ -0,0 +1,929 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+DOCUMENTATION = '''
+---
+module: nxos_pim_interface
+version_added: "2.2"
+short_description: Manages PIM interface configuration.
+description:
+    - Manages PIM interface configuration settings.
+extends_documentation_fragment: nxos
+author:
+    - Jason Edelman (@jedelman8)
+notes:
+    - When C(state=default), supported params will be reset to a default state.
+      These include C(dr_prio), C(hello_auth_key), C(hello_interval), C(jp_policy_out),
+      C(jp_policy_in), C(jp_type_in), C(jp_type_out), C(border), C(neighbor_policy),
+      C(neighbor_type).
+    - The C(hello_auth_key) param is not idempotent.
+    - C(hello_auth_key) only supports clear text passwords.
+    - When C(state=absent), pim interface configuration will be set to defaults and pim-sm
+      will be disabled on the interface.
+    - PIM must be enabled on the device to use this module.
+    - This module is for Layer 3 interfaces.
+options:
+    interface:
+        description:
+            - Full name of the interface such as Ethernet1/33.
+        required: true
+    sparse:
+        description:
+            - Enable/disable sparse-mode on the interface.
+        required: false
+        default: true
+        choices: ['true', 'false']
+    hello_auth_key:
+        description:
+            - Authentication for hellos on this interface.
+        required: false
+        default: null
+    hello_interval:
+        description:
+            - Hello interval in milliseconds for this interface.
+        required: false
+        default: null
+        choices: ['true', 'false']
+    jp_policy_out:
+        description:
+            - Policy for join-prune messages (outbound).
+        required: true
+        default: null
+    jp_policy_in:
+        description:
+            - Policy for join-prune messages (inbound).
+        required: false
+        default: null
+    jp_type_out:
+        description:
+            - Type of policy mapped to C(jp_policy_out).
+        required: false
+        default: null
+        choices: ['prefix', 'routemap']
+    jp_type_in:
+        description:
+            - Type of policy mapped to C(jp_policy_in).
+        required: false
+        default: null
+        choices: ['prefix', 'routemap']
+    border:
+        description:
+            - Configures interface to be a boundary of a PIM domain.
+        required: false
+        default: null
+        choices: ['true', 'false']
+    neighbor_policy:
+        description:
+            - Configures a neighbor policy for filtering adjacencies.
+        required: false
+        default: null
+    neighbor_type:
+        description:
+            - Type of policy mapped to neighbor_policy.
+        required: false
+        default: null
+        choices: ['prefix', 'routemap']
+    state:
+        description:
+            - Manages desired state of the resource.
+        required: false
+        default: present
+        choices: ['present', 'default']
+'''
+EXAMPLES = '''
+# ensure PIM is not running on the interface
+- nxos_pim_interface:
+    interface=eth1/33
+    state=absent
+    host={{ inventory_hostname }}
+    username={{ un }}
+    password={{ pwd }}
+
+# ensure the interface has pim-sm enabled with the appropriate priority and hello interval
+- nxos_pim_interface:
+    interface=eth1/33
+    dr_prio=10
+    hello_interval=40
+    state=present
+    host={{ inventory_hostname }}
+    username={{ un }}
+    password={{ pwd }}
+
+# ensure join-prune policies exist
+- nxos_pim_interface:
+    interface=eth1/33
+    jp_policy_in=JPIN
+    jp_policy_out=JPOUT
+    jp_type_in=routemap
+    jp_type_out=routemap
+    host={{ inventory_hostname }}
+    username={{ un }}
+    password={{ pwd }}
+
+# ensure defaults are in place
+- nxos_pim_interface:
+    interface=eth1/33
+    state=default
+    host={{ inventory_hostname }}
+    username={{ un }}
+    password={{ pwd }}
+'''
+
+RETURN = '''
+proposed:
+    description: k/v pairs of parameters passed into module
+    returned: always
+    type: dict
+    sample: {"interface": "eth1/33", "neighbor_policy": "test", 
+            "neighbor_type": "routemap", "sparse": true}
+existing:
+    description:
+        - k/v pairs of existing configuration
+    type: dict
+    sample: {"border": false, "dr_prio": "1", "hello_interval": "30000", 
+            "isauth": false, "jp_bidir": false, "jp_policy_in": "JPIN", 
+            "jp_policy_out": "1", "jp_type_in": "routemap", 
+            "jp_type_out": null, "neighbor_policy": "test1", 
+            "neighbor_type": "prefix", "sparse": true}
+end_state:
+    description: k/v pairs of configuration after module execution
+    returned: always
+    type: dict
+    sample: {"border": false, "dr_prio": "1", "hello_interval": "30000", 
+            "isauth": false, "jp_bidir": false, "jp_policy_in": "JPIN", 
+            "jp_policy_out": "1", "jp_type_in": "routemap", 
+            "jp_type_out": null, "neighbor_policy": "test", 
+            "neighbor_type": "routemap", "sparse": true}
+updates:
+    description: command sent to the device
+    returned: always
+    type: list
+    sample: ["interface eth1/33", "ip pim neighbor-policy test", 
+            "ip pim neighbor-policy test"]
+changed:
+    description: check to see if a change was made on the device
+    returned: always
+    type: boolean
+    sample: true
+'''
+
+
+import json
+import time
+
+# COMMON CODE FOR MIGRATION
+import re
+
+from ansible.module_utils.basic import get_exception
+from ansible.module_utils.netcfg import NetworkConfig, ConfigLine
+from ansible.module_utils.shell import ShellError
+
+try:
+    from ansible.module_utils.nxos import get_module
+except ImportError:
+    from ansible.module_utils.nxos import NetworkModule
+
+
+def to_list(val):
+     if isinstance(val, (list, tuple)):
+         return list(val)
+     elif val is not None:
+         return [val]
+     else:
+         return list()
+
+
+class CustomNetworkConfig(NetworkConfig):
+
+    def expand_section(self, configobj, S=None):
+        if S is None:
+            S = list()
+        S.append(configobj)
+        for child in configobj.children:
+            if child in S:
+                continue
+            self.expand_section(child, S)
+        return S
+
+    def get_object(self, path):
+        for item in self.items:
+            if item.text == path[-1]:
+                parents = [p.text for p in item.parents]
+                if parents == path[:-1]:
+                    return item
+
+    def to_block(self, section):
+        return '\n'.join([item.raw for item in section])
+
+    def get_section(self, path):
+        try:
+            section = self.get_section_objects(path)
+            return self.to_block(section)
+        except ValueError:
+            return list()
+
+    def get_section_objects(self, path):
+        if not isinstance(path, list):
+            path = [path]
+        obj = self.get_object(path)
+        if not obj:
+            raise ValueError('path does not exist in config')
+        return self.expand_section(obj)
+
+
+    def add(self, lines, parents=None):
+        """Adds one or lines of configuration
+        """
+
+        ancestors = list()
+        offset = 0
+        obj = None
+
+        ## global config command
+        if not parents:
+            for line in to_list(lines):
+                item = ConfigLine(line)
+                item.raw = line
+                if item not in self.items:
+                    self.items.append(item)
+
+        else:
+            for index, p in enumerate(parents):
+                try:
+                    i = index + 1
+                    obj = self.get_section_objects(parents[:i])[0]
+                    ancestors.append(obj)
+
+                except ValueError:
+                    # add parent to config
+                    offset = index * self.indent
+                    obj = ConfigLine(p)
+                    obj.raw = p.rjust(len(p) + offset)
+                    if ancestors:
+                        obj.parents = list(ancestors)
+                        ancestors[-1].children.append(obj)
+                    self.items.append(obj)
+                    ancestors.append(obj)
+
+            # add child objects
+            for line in to_list(lines):
+                # check if child already exists
+                for child in ancestors[-1].children:
+                    if child.text == line:
+                        break
+                else:
+                    offset = len(parents) * self.indent
+                    item = ConfigLine(line)
+                    item.raw = line.rjust(len(line) + offset)
+                    item.parents = ancestors
+                    ancestors[-1].children.append(item)
+                    self.items.append(item)
+
+
+def get_network_module(**kwargs):
+    try:
+        return get_module(**kwargs)
+    except NameError:
+        return NetworkModule(**kwargs)
+
+def get_config(module, include_defaults=False):
+    config = module.params['config']
+    if not config:
+        try:
+            config = module.get_config()
+        except AttributeError:
+            defaults = module.params['include_defaults']
+            config = module.config.get_config(include_defaults=defaults)
+    return CustomNetworkConfig(indent=2, contents=config)
+
+def load_config(module, candidate):
+    config = get_config(module)
+
+    commands = candidate.difference(config)
+    commands = [str(c).strip() for c in commands]
+
+    save_config = module.params['save']
+
+    result = dict(changed=False)
+
+    if commands:
+        if not module.check_mode:
+            try:
+                module.configure(commands)
+            except AttributeError:
+                module.config(commands)
+
+            if save_config:
+                try:
+                    module.config.save_config()
+                except AttributeError:
+                    module.execute(['copy running-config startup-config'])
+
+        result['changed'] = True
+        result['updates'] = commands
+
+    return result
+# END OF COMMON CODE
+
+
+def execute_config_command(commands, module):
+    try:
+        module.configure(commands)
+    except ShellError:
+        clie = get_exception()
+        module.fail_json(msg='Error sending CLI commands',
+                         error=str(clie), commands=commands)
+    except AttributeError:
+        try:
+            commands.insert(0, 'configure')
+            module.cli.add_commands(commands, output='config')
+            module.cli.run_commands()
+        except ShellError:
+            clie = get_exception()
+            module.fail_json(msg='Error sending CLI commands',
+                             error=str(clie), commands=commands)
+
+
+def get_cli_body_ssh(command, response, module, text=False):
+    """Get response for when transport=cli.  This is kind of a hack and mainly
+    needed because these modules were originally written for NX-API.  And
+    not every command supports "| json" when using cli/ssh.  As such, we assume
+    if | json returns an XML string, it is a valid command, but that the
+    resource doesn't exist yet. Instead, the output will be a raw string
+    when issuing commands containing 'show run'.
+    """
+    if 'xml' in response[0] or response[0] == '\n' or '^' in response[0]:
+        body = []
+    elif 'show run' in command or text:
+        body = response
+    else:
+        try:
+            if isinstance(response[0], str):
+                body = [json.loads(response[0])]
+            else:
+                body = response
+        except ValueError:
+            module.fail_json(msg='Command does not support JSON output',
+                             command=command)
+    return body
+
+
+def execute_show(cmds, module, command_type=None):
+    command_type_map = {
+        'cli_show': 'json',
+        'cli_show_ascii': 'text'
+    }
+
+    try:
+        if command_type:
+            response = module.execute(cmds, command_type=command_type)
+        else:
+            response = module.execute(cmds)
+    except ShellError:
+        clie = get_exception()
+        module.fail_json(msg='Error sending {0}'.format(cmds),
+                         error=str(clie))
+    except AttributeError:
+        try:
+            if command_type:
+                command_type = command_type_map.get(command_type)
+                module.cli.add_commands(cmds, output=command_type)
+                response = module.cli.run_commands()
+            else:
+                module.cli.add_commands(cmds)
+                response = module.cli.run_commands()
+        except ShellError:
+            clie = get_exception()
+            module.fail_json(msg='Error sending {0}'.format(cmds),
+                             error=str(clie))
+    return response
+
+
+def execute_show_command(command, module, command_type='cli_show', text=False):
+    if module.params['transport'] == 'cli':
+        if 'show run' not in command and text is False:
+            command += ' | json'
+        cmds = [command]
+        response = execute_show(cmds, module)
+        body = get_cli_body_ssh(command, response, module, text=text)
+    elif module.params['transport'] == 'nxapi':
+        cmds = [command]
+        body = execute_show(cmds, module, command_type=command_type)
+
+    return body
+
+
+def flatten_list(command_lists):
+    flat_command_list = []
+    for command in command_lists:
+        if isinstance(command, list):
+            flat_command_list.extend(command)
+        else:
+            flat_command_list.append(command)
+    return flat_command_list
+
+
+def local_existing(gexisting):
+    jp_bidir = False
+    isauth = False
+    if gexisting:
+        jp_bidir = gexisting.get('jp_bidir')
+        isauth = gexisting.get('isauth')
+        if jp_bidir and isauth:
+            gexisting.pop('jp_bidir')
+            gexisting.pop('isauth')
+        gexisting['sparse'] = True
+
+    return gexisting, jp_bidir, isauth
+
+
+def get_interface_type(interface):
+    if interface.upper().startswith('ET'):
+        return 'ethernet'
+    elif interface.upper().startswith('VL'):
+        return 'svi'
+    elif interface.upper().startswith('LO'):
+        return 'loopback'
+    elif interface.upper().startswith('MG'):
+        return 'management'
+    elif interface.upper().startswith('MA'):
+        return 'management'
+    elif interface.upper().startswith('PO'):
+        return 'portchannel'
+    else:
+        return 'unknown'
+
+
+def get_interface_mode(interface, intf_type, module):
+    command = 'show interface {0}'.format(interface)
+    mode = 'unknown'
+    interface_table = {}
+    body = execute_show_command(command, module)
+
+    try:
+        interface_table = body[0]['TABLE_interface']['ROW_interface']
+    except (KeyError, AttributeError, IndexError):
+        return mode
+
+    if intf_type in ['ethernet', 'portchannel']:
+        mode = str(interface_table.get('eth_mode', 'layer3'))
+        if mode in ['access', 'trunk']:
+            mode = 'layer2'
+        elif mode == 'routed':
+            mode = 'layer3'
+    elif intf_type in ['loopback', 'svi']:
+        mode = 'layer3'
+    return mode
+
+
+def get_pim_interface(module, interface):
+    pim_interface = {}
+    command = 'show ip pim interface {0}'.format(interface)
+    
+    body = execute_show_command(command, module,
+                                command_type='cli_show_ascii', text=True)
+    
+    if body:
+        if 'not running' not in body[0]:
+            body = execute_show_command(command, module)
+
+    try:
+        get_data = body[0]['TABLE_iod']['ROW_iod']
+
+        if isinstance(get_data.get('dr-priority'), unicode) or \
+                isinstance(get_data.get('dr-priority'), str):
+            pim_interface['dr_prio'] = get_data.get('dr-priority')
+        else:
+            pim_interface['dr_prio'] = get_data.get('dr-priority')[0]
+
+        hello_interval = get_data.get('hello-interval-sec')
+        if hello_interval:
+            hello_interval_msec = int(get_data.get('hello-interval-sec'))*1000
+        pim_interface['hello_interval'] = str(hello_interval_msec)
+        border = get_data.get('is-border')
+
+        if border == 'true':
+            pim_interface['border'] = True
+        elif border == 'false':
+            pim_interface['border'] = False
+
+        isauth = get_data.get('isauth-config')
+        if isauth == 'true':
+            pim_interface['isauth'] = True
+        elif isauth == 'false':
+            pim_interface['isauth'] = False
+
+        pim_interface['neighbor_policy'] = get_data.get('nbr-policy-name')
+        if pim_interface['neighbor_policy'] == 'none configured':
+            pim_interface['neighbor_policy'] = None
+
+        jp_in_policy = get_data.get('jp-in-policy-name')
+        pim_interface['jp_policy_in'] = jp_in_policy
+        if jp_in_policy == 'none configured':
+            pim_interface['jp_policy_in'] = None
+
+        if isinstance(get_data.get('jp-out-policy-name'), unicode) or \
+                isinstance(get_data.get('jp-out-policy-name'), str):
+            pim_interface['jp_policy_out'] = get_data.get('jp-out-policy-name')
+        else:
+            pim_interface['jp_policy_out'] = get_data.get(
+                'jp-out-policy-name')[0]
+
+        if pim_interface['jp_policy_out'] == 'none configured':
+            pim_interface['jp_policy_out'] = None
+
+    except (KeyError, AttributeError, TypeError, IndexError):
+        return {}
+
+    command = 'show run interface {0}'.format(interface)
+    
+    body = execute_show_command(command, module, command_type='cli_show_ascii')
+
+    jp_configs = []
+    neigh = None
+    if body:
+        all_lines = body[0].splitlines()
+
+        for each in all_lines:
+            if 'jp-policy' in each:
+                jp_configs.append(str(each.strip()))
+            elif 'neighbor-policy' in each:
+                neigh = str(each)
+
+    pim_interface['neighbor_type'] = None
+    neigh_type = None
+    if neigh:
+        if 'prefix-list' in neigh:
+            neigh_type = 'prefix'
+        else:
+            neigh_type = 'routemap'
+    pim_interface['neighbor_type'] = neigh_type
+
+    len_existing = len(jp_configs)
+    list_of_prefix_type = len([x for x in jp_configs if 'prefix-list' in x])
+    jp_type_in = None
+    jp_type_out = None
+    jp_bidir = False
+    if len_existing == 1:
+        # determine type
+        last_word = jp_configs[0].split(' ')[-1]
+        if last_word == 'in':
+            if list_of_prefix_type:
+                jp_type_in = 'prefix'
+            else:
+                jp_type_in = 'routemap'
+        elif last_word == 'out':
+            if list_of_prefix_type:
+                jp_type_out = 'prefix'
+            else:
+                jp_type_out = 'routemap'
+        else:
+            jp_bidir = True
+            if list_of_prefix_type:
+                jp_type_in = 'prefix'
+                jp_type_out = 'routemap'
+            else:
+                jp_type_in = 'routemap'
+                jp_type_out = 'routemap'
+    else:
+        for each in jp_configs:
+            last_word = each.split(' ')[-1]
+            if last_word == 'in':
+                if 'prefix-list' in each:
+                    jp_type_in = 'prefix'
+                else:
+                    jp_type_in = 'routemap'
+            elif last_word == 'out':
+                if 'prefix-list' in each:
+                    jp_type_out = 'prefix'
+                else:
+                    jp_type_out = 'routemap'
+
+    pim_interface['jp_type_in'] = jp_type_in
+    pim_interface['jp_type_out'] = jp_type_out
+    pim_interface['jp_bidir'] = jp_bidir
+
+    return pim_interface
+
+
+def fix_delta(delta, existing):
+    if delta.get('sparse') is False and existing.get('sparse') is None:
+        delta.pop('sparse')
+    return delta
+
+
+def config_pim_interface(delta, existing, jp_bidir, isauth):
+    command = None
+    commands = []
+
+    delta = fix_delta(delta, existing)
+
+    CMDS = {
+        'sparse': 'ip pim sparse-mode',
+        'dr_prio': 'ip pim dr-priority {0}',
+        'hello_interval': 'ip pim hello-interval {0}',
+        'hello_auth_key': 'ip pim hello-authentication ah-md5 {0}',
+        'border': 'ip pim border',
+        'jp_policy_out': 'ip pim jp-policy prefix-list {0} out',
+        'jp_policy_in': 'ip pim jp-policy prefix-list {0} in',
+        'jp_type_in': '',
+        'jp_type_out': '',
+        'neighbor_policy': 'ip pim neighbor-policy prefix-list {0}',
+        'neighbor_type': ''
+    }
+
+    if jp_bidir:
+        if delta.get('jp_policy_in') or delta.get('jp_policy_out'):
+            if existing.get('jp_type_in') == 'prefix':
+                command = 'no ip pim jp-policy prefix-list {0}'.format(
+                    existing.get('jp_policy_in')
+                    )
+            else:
+                command = 'no ip pim jp-policy {0}'.format(
+                    existing.get('jp_policy_in')
+                    )
+            if command:
+                commands.append(command)
+
+    for k, v in delta.iteritems():
+        if k in ['dr_prio', 'hello_interval', 'hello_auth_key', 'border',
+                 'sparse']:
+            if v:
+                command = CMDS.get(k).format(v)
+            elif k == 'hello_auth_key':
+                if isauth:
+                    command = 'no ip pim hello-authentication ah-md5'
+            else:
+                command = 'no ' + CMDS.get(k).format(v)
+
+            if command:
+                commands.append(command)
+        elif k in ['neighbor_policy', 'jp_policy_in', 'jp_policy_out',
+                   'neighbor_type']:
+            if k in ['neighbor_policy', 'neighbor_type']:
+                temp = delta.get('neighbor_policy') or existing.get(
+                    'neighbor_policy')
+                if delta.get('neighbor_type') == 'prefix':
+                    command = CMDS.get(k).format(temp)
+                elif delta.get('neighbor_type') == 'routemap':
+                    command = 'ip pim neighbor-policy {0}'.format(temp)
+                elif existing.get('neighbor_type') == 'prefix':
+                    command = CMDS.get(k).format(temp)
+                elif existing.get('neighbor_type') == 'routemap':
+                    command = 'ip pim neighbor-policy {0}'.format(temp)
+            elif k in ['jp_policy_in', 'jp_type_in']:
+                temp = delta.get('jp_policy_in') or existing.get(
+                    'jp_policy_in')
+                if delta.get('jp_type_in') == 'prefix':
+                    command = CMDS.get(k).format(temp)
+                elif delta.get('jp_type_in') == 'routemap':
+                    command = 'ip pim jp-policy {0} in'.format(temp)
+                elif existing.get('jp_type_in') == 'prefix':
+                    command = CMDS.get(k).format(temp)
+                elif existing.get('jp_type_in') == 'routemap':
+                    command = 'ip pim jp-policy {0} in'.format(temp)
+            elif k in ['jp_policy_out', 'jp_type_out']:
+                temp = delta.get('jp_policy_out') or existing.get(
+                    'jp_policy_out')
+                if delta.get('jp_type_out') == 'prefix':
+                    command = CMDS.get(k).format(temp)
+                elif delta.get('jp_type_out') == 'routemap':
+                    command = 'ip pim jp-policy {0} out'.format(temp)
+                elif existing.get('jp_type_out') == 'prefix':
+                    command = CMDS.get(k).format(temp)
+                elif existing.get('jp_type_out') == 'routemap':
+                    command = 'ip pim jp-policy {0} out'.format(temp)
+            if command:
+                commands.append(command)
+        command = None
+
+    return commands
+
+
+def get_pim_interface_defaults():
+    dr_prio = '1'
+    border = False
+    hello_interval = '30000'
+    hello_auth_key = False
+
+    args = dict(dr_prio=dr_prio, border=border,
+                hello_interval=hello_interval,
+                hello_auth_key=hello_auth_key)
+
+    default = dict((param, value) for (param, value) in args.iteritems()
+                   if value is not None)
+
+    return default
+
+
+def default_pim_interface_policies(existing, jp_bidir):
+    commands = []
+
+    if jp_bidir:
+        if existing.get('jp_policy_in') or existing.get('jp_policy_out'):
+                if existing.get('jp_type_in') == 'prefix':
+                    command = 'no ip pim jp-policy prefix-list {0}'.format(
+                        existing.get('jp_policy_in')
+                        )
+        if command:
+            commands.append(command)
+
+    elif not jp_bidir:
+        command = None
+        for k, v in existing.iteritems():
+            if k == 'jp_policy_in':
+                if existing.get('jp_policy_in'):
+                    if existing.get('jp_type_in') == 'prefix':
+                        command = 'no ip pim jp-policy prefix-list {0} in'.format(
+                            existing.get('jp_policy_in')
+                            )
+                    else:
+                        command = 'no ip pim jp-policy {0} in'.format(
+                            existing.get('jp_policy_in')
+                            )
+            elif k == 'jp_policy_out':
+                if existing.get('jp_policy_out'):
+                    if existing.get('jp_type_out') == 'prefix':
+                        command = 'no ip pim jp-policy prefix-list {0} out'.format(
+                            existing.get('jp_policy_out')
+                            )
+                    else:
+                        command = 'no ip pim jp-policy {0} out'.format(
+                            existing.get('jp_policy_out')
+                            )
+            if command:
+                commands.append(command)
+            command = None
+
+    if existing.get('neighbor_policy'):
+        command = 'no ip pim neighbor-policy'
+        commands.append(command)
+
+    return commands
+
+
+def config_pim_interface_defaults(existing, jp_bidir, isauth):
+    command = []
+
+    # returns a dict
+    defaults = get_pim_interface_defaults()
+    delta = dict(set(defaults.iteritems()).difference(
+                                                     existing.iteritems()))
+    if delta:
+        # returns a list
+        command = config_pim_interface(delta, existing,
+                                       jp_bidir, isauth)
+    comm = default_pim_interface_policies(existing, jp_bidir)
+    if comm:
+        for each in comm:
+            command.append(each)
+
+    return command
+
+
+def main():
+    argument_spec=dict(
+            interface=dict(required=True),
+            sparse=dict(type='bool', default=True),
+            dr_prio=dict(),
+            hello_auth_key=dict(),
+            hello_interval=dict(type='int'),
+            jp_policy_out=dict(),
+            jp_policy_in=dict(),
+            jp_type_out=dict(choices=['prefix', 'routemap']),
+            jp_type_in=dict(choices=['prefix', 'routemap']),
+            border=dict(type='bool'),
+            neighbor_policy=dict(),
+            neighbor_type=dict(choices=['prefix', 'routemap']),
+            state=dict(choices=['present', 'absent', 'default'],
+                       default='present'),
+    )
+    module = get_network_module(argument_spec=argument_spec,
+                                supports_check_mode=True)
+
+    state = module.params['state']
+
+    sparse = module.params['sparse']
+    interface = module.params['interface']
+    jp_type_in = module.params['jp_type_in']
+    jp_type_out = module.params['jp_type_out']
+    jp_policy_in = module.params['jp_policy_in']
+    jp_policy_out = module.params['jp_policy_out']
+    neighbor_policy = module.params['neighbor_policy']
+    neighbor_type = module.params['neighbor_type']
+    hello_interval = module.params['hello_interval']
+
+    intf_type = get_interface_type(interface)
+    if get_interface_mode(interface, intf_type, module) == 'layer2':
+        module.fail_json(msg='this module only works on Layer 3 interfaces.')
+
+    if jp_policy_in:
+        if not jp_type_in:
+            module.fail_json(msg='jp_type_in required when using jp_policy_in.')
+    if jp_policy_out:
+        if not jp_type_out:
+            module.fail_json(msg='jp_type_out required when using '
+                                 ' jp_policy_out.')
+    if neighbor_policy:
+        if not neighbor_type:
+            module.fail_json(msg='neighbor_type required when using '
+                                 'neighbor_policy.')
+
+    get_existing = get_pim_interface(module, interface)
+    existing, jp_bidir, isauth = local_existing(get_existing)
+    end_state = existing
+    changed = False
+
+    commands = []
+
+    args = [
+        'interface',
+        'sparse',
+        'dr_prio',
+        'hello_auth_key',
+        'hello_interval',
+        'jp_policy_out',
+        'jp_type_out',
+        'jp_type_in',
+        'jp_policy_in',
+        'border',
+        'neighbor_type',
+        'neighbor_policy'
+        ]
+    proposed = dict((k, v) for k, v in module.params.iteritems()
+                    if v is not None and k in args)
+
+    '''
+    CANNOT_ABSENT = ['dr_prio', 'hello_interval',
+                     'hello_auth_key', 'jp_policy_out', 'jp_policy_in',
+                     'jp_type_out', 'jp_type_in', 'border', 'neighbor_type',
+                     'neighbor_policy']
+    '''
+
+    if hello_interval:
+        proposed['hello_interval'] = str(proposed['hello_interval'] * 1000)
+
+    delta = dict(set(proposed.iteritems()).difference(existing.iteritems()))
+
+    if state == 'present':
+        if delta:
+            command = config_pim_interface(delta, existing, jp_bidir, isauth)
+            if command:
+                commands.append(command)
+    elif state == 'default':
+        defaults = config_pim_interface_defaults(existing, jp_bidir, isauth)
+        if defaults:
+            commands.append(defaults)
+
+    elif state == 'absent':
+        if existing.get('sparse') == True:
+            delta['sparse'] = False
+            # defaults is a list of commands
+            defaults = config_pim_interface_defaults(existing, jp_bidir, isauth)
+            if defaults:
+                commands.append(defaults)
+
+            command = config_pim_interface(delta, existing, jp_bidir, isauth)
+            commands.append(command)
+
+    if commands:
+        commands.insert(0, ['interface {0}'.format(interface)])
+
+    cmds = flatten_list(commands)
+    results = {}
+    if cmds:
+        if module.check_mode:
+            module.exit_json(changed=True, commands=cmds)
+        else:
+            changed = True
+            execute_config_command(cmds, module)
+            time.sleep(1)
+            get_existing = get_pim_interface(module, interface)
+            end_state, jp_bidir, isauth = local_existing(get_existing)
+
+    results['proposed'] = proposed
+    results['existing'] = existing
+    results['updates'] = cmds
+    results['changed'] = changed
+    results['end_state'] = end_state
+
+    module.exit_json(**results)
+
+
+if __name__ == '__main__':
+    main()
\ No newline at end of file