summaryrefslogtreecommitdiff
path: root/python/vyos/configinterface.py
blob: 843d1c7391beacd8a6577a7543eda920638a3556 (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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see <http://www.gnu.org/licenses/>.

import os
import vyos.validate

def validate_mac_address(addr):
    # a mac address consits out of 6 octets
    octets = len(addr.split(':'))
    if octets != 6:
        raise ValueError('wrong number of MAC octets: {} '.format(octets))

    # validate against the first mac address byte if it's a multicast address
    if int(addr.split(':')[0]) & 1:
        raise ValueError('{} is a multicast MAC address'.format(addr))

    # overall mac address is not allowed to be 00:00:00:00:00:00
    if sum(int(i, 16) for i in addr.split(':')) == 0:
        raise ValueError('00:00:00:00:00:00 is not a valid MAC address')

    # check for VRRP mac address
    if addr.split(':')[0] == '0' and addr.split(':')[1] == '0' and addr.split(':')[2] == '94' and addr.split(':')[3] == '0' and addr.split(':')[4] == '1':
        raise ValueError('{} is a VRRP MAC address')

    pass

def set_mac_address(intf, addr):
    """
    Configure interface mac address using iproute2 command
    """
    validate_mac_address(addr)

    os.system('ip link set {} address {}'.format(intf, addr))
    pass

def set_description(intf, desc):
    """
    Sets the interface secription reported usually by SNMP
    """
    with open('/sys/class/net/' + intf + '/ifalias', 'w') as f:
      f.write(desc)

    pass

def set_arp_cache_timeout(intf, tmoMS):
    """
    Configure the ARP cache entry timeout in milliseconds
    """
    with open('/proc/sys/net/ipv4/neigh/' + intf + '/base_reachable_time_ms', 'w') as f:
      f.write(tmoMS)

    pass

def set_multicast_querier(intf, enable):
    """
    Sets whether the bridge actively runs a multicast querier or not. When a
    bridge receives a 'multicast host membership' query from another network host,
    that host is tracked based on the time that the query was received plus the
    multicast query interval time.

    use enable=1 to enable or enable=0 to disable
    """

    if int(enable) >= 0 and int(enable) <= 1:
      with open('/sys/devices/virtual/net/' + intf + '/bridge/multicast_querier', 'w') as f:
        f.write(str(enable))
    else:
      raise ValueError("malformed configuration string on interface {}: enable={}".format(intf, enable))

    pass

def set_link_detect(intf, enable):
    """
    0 - Allow packets to be received for the address on this interface
    even if interface is disabled or no carrier.

    1 - Ignore packets received if interface associated with the incoming
    address is down.

    2 - Ignore packets received if interface associated with the incoming
    address is down or has no carrier.

    Kernel Source: Documentation/networking/ip-sysctl.txt
    """

    # Note can't use sysctl it is broken for vif name because of dots
    # link_filter values:
    #   0 - always receive
    #   1 - ignore receive if admin_down
    #   2 - ignore receive if admin_down or link down

    with open('/proc/sys/net/ipv4/conf/' + intf + '/link_filter', 'w') as f:
      if enable == True or enable == 1:
        f.write('2')
        if os.path.isfile('/usr/bin/vtysh'):
          os.system('/usr/bin/vtysh -c "configure terminal" -c "interface {}" -c "link-detect"'.format(intf))
      else:
        f.write('1')
        if os.path.isfile('/usr/bin/vtysh'):
          os.system('/usr/bin/vtysh -c "configure terminal" -c "interface {}" -c "no link-detect"'.format(intf))

    pass

def add_interface_address(intf, addr):
    """
    Configure an interface IPv4/IPv6 address
    """
    if addr == "dhcp":
        os.system('/opt/vyatta/sbin/vyatta-interfaces.pl --dev="{}" --dhcp=start'.format(intf))
    elif addr == "dhcpv6":
        os.system('/opt/vyatta/sbin/vyatta-dhcpv6-client.pl --start -ifname "{}"'.format(intf))
    elif vyos.validate.is_ipv4(addr):
        if not vyos.validate.is_intf_addr_assigned(intf, addr):
            print("Assigning {} to {}".format(addr, intf))
            os.system('sudo ip -4 addr add "{}" broadcast + dev "{}"'.format(addr, intf))
    elif vyos.validate.is_ipv6(addr):
        if not vyos.validate.is_intf_addr_assigned(intf, addr):
            print("Assigning {} to {}".format(addr, intf))
            os.system('sudo ip -6 addr add "{}" dev "{}"'.format(addr, intf))
    else:
        raise ConfigError('{} is not a valid interface address'.format(addr))

    pass

def remove_interface_address(intf, addr):
    """
    Remove IPv4/IPv6 address from given interface
    """

    if addr == "dhcp":
        os.system('/opt/vyatta/sbin/vyatta-interfaces.pl --dev="{}" --dhcp=stop'.format(intf))
    elif addr == "dhcpv6":
        os.system('/opt/vyatta/sbin/vyatta-dhcpv6-client.pl --stop -ifname "{}"'.format(intf))
    elif vyos.validate.is_ipv4(addr):
        os.system('ip -4 addr del "{}" dev "{}"'.format(addr, intf))
    elif vyos.validate.is_ipv6(addr):
        os.system('ip -6 addr del "{}" dev "{}"'.format(addr, intf))
    else:
        raise ConfigError('{} is not a valid interface address'.format(addr))

    pass

def remove_interface(ifname):
    """
    Remove given interface from operating system, e.g. 'dum0'
    """

    if os.path.isdir('/sys/class/net/' + ifname):
        os.system('ip link delete "{}"'.format(ifname))

    pass

def add_interface(type, ifname):
    """
    Add given interface to operating system, e.g. add 'dummy' interface with
    name 'dum0'
    """

    if not os.path.isdir('/sys/class/net/' + ifname):
        os.system('ip link add "{}" type "{}"'.format(ifname, type))

    pass