summaryrefslogtreecommitdiff
path: root/src/conf_mode/igmp_proxy.py
blob: 90f3f30a8eeb552589035701fa1ed9ebff49ac49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/usr/bin/env python3
#
# Copyright (C) 2018-2020 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

import os

from sys import exit
from netifaces import interfaces

from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.template import render
from vyos.util import call
from vyos.util import dict_search
from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()

config_file = r'/etc/igmpproxy.conf'

def get_config(config=None):
    if config:
        conf = config
    else:
        conf = Config()

    base = ['protocols', 'igmp-proxy']
    igmp_proxy = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)

    if 'interface' in igmp_proxy:
        # T2665: we must add the tagNode defaults individually until this is
        # moved to the base class
        default_values = defaults(base + ['interface'])
        for interface in igmp_proxy['interface']:
            igmp_proxy['interface'][interface] = dict_merge(default_values,
                igmp_proxy['interface'][interface])


    if conf.exists(['protocols', 'igmp']):
        igmp_proxy.update({'igmp_configured': ''})

    if conf.exists(['protocols', 'pim']):
        igmp_proxy.update({'pim_configured': ''})

    return igmp_proxy

def verify(igmp_proxy):
    # bail out early - looks like removal from running config
    if not igmp_proxy or 'disable' in igmp_proxy:
        return None

    if 'igmp_configured' in igmp_proxy or 'pim_configured' in igmp_proxy:
        raise ConfigError('Can not configure both IGMP proxy and PIM '\
                          'at the same time')

    # at least two interfaces are required, one upstream and one downstream
    if 'interface' not in igmp_proxy or len(igmp_proxy['interface']) < 2:
        raise ConfigError('Must define exactly one upstream and at least one ' \
                          'downstream interface!')

    upstream = 0
    for interface, config in igmp_proxy['interface'].items():
        if interface not in interfaces():
            raise ConfigError(f'Interface "{interface}" does not exist')
        if dict_search('role', config) == 'upstream':
            upstream += 1

    if upstream == 0:
        raise ConfigError('At least 1 upstream interface is required!')
    elif upstream > 1:
        raise ConfigError('Only 1 upstream interface allowed!')

    return None

def generate(igmp_proxy):
    # bail out early - looks like removal from running config
    if not igmp_proxy:
        return None

    # bail out early - service is disabled, but inform user
    if 'disable' in igmp_proxy:
        print('WARNING: IGMP Proxy will be deactivated because it is disabled')
        return None

    render(config_file, 'igmp-proxy/igmpproxy.conf.tmpl', igmp_proxy,
           trim_blocks=True)

    return None

def apply(igmp_proxy):
    if not igmp_proxy or 'disable' in igmp_proxy:
         # IGMP Proxy support is removed in the commit
         call('systemctl stop igmpproxy.service')
         if os.path.exists(config_file):
             os.unlink(config_file)
    else:
        call('systemctl restart igmpproxy.service')

    return None

if __name__ == '__main__':
    try:
        c = get_config()
        verify(c)
        generate(c)
        apply(c)
    except ConfigError as e:
        print(e)
        exit(1)