From f16633f0ef2dd074c24387cbd2b9d5541297509c Mon Sep 17 00:00:00 2001 From: Dmytro Aleksandrov Date: Mon, 19 Aug 2019 18:53:33 +0300 Subject: T1596 rewrite 'telnet' and 'traceroute' operations to xml style --- debian/control | 3 +++ 1 file changed, 3 insertions(+) (limited to 'debian') diff --git a/debian/control b/debian/control index a65d0158e..41b402fc1 100644 --- a/debian/control +++ b/debian/control @@ -61,6 +61,9 @@ Depends: python3, openvpn, openvpn-auth-ldap, openvpn-auth-radius, + mtr-tiny, + telnet, + traceroute, ${shlibs:Depends}, ${misc:Depends} Description: VyOS configuration scripts and data -- cgit v1.2.3 From e5df80a3f54da23858c382a8e491ff9901317e1e Mon Sep 17 00:00:00 2001 From: Daniil Baturin Date: Tue, 20 Aug 2019 18:53:35 +0200 Subject: T1598: initial implementation of the hosts keeper daemon. --- debian/control | 1 + python/vyos/hostsd_client.py | 56 +++++++++ src/services/vyos-hostsd | 254 ++++++++++++++++++++++++++++++++++++++++ src/systemd/vyos-hostsd.service | 22 ++++ src/utils/vyos-hostsd-client | 82 +++++++++++++ 5 files changed, 415 insertions(+) create mode 100644 python/vyos/hostsd_client.py create mode 100755 src/services/vyos-hostsd create mode 100644 src/systemd/vyos-hostsd.service create mode 100755 src/utils/vyos-hostsd-client (limited to 'debian') diff --git a/debian/control b/debian/control index a65d0158e..f46e5d08e 100644 --- a/debian/control +++ b/debian/control @@ -28,6 +28,7 @@ Depends: python3, python3-hurry.filesize, python3-vici (>= 5.7.2), python3-bottle, + python3-zmq, ipaddrcheck, tcpdump, tshark, diff --git a/python/vyos/hostsd_client.py b/python/vyos/hostsd_client.py new file mode 100644 index 000000000..e02aefe6f --- /dev/null +++ b/python/vyos/hostsd_client.py @@ -0,0 +1,56 @@ +import json + +import zmq + + +SOCKET_PATH = "ipc:///run/vyos-hostsd.sock" + + +class VyOSHostsdError(Exception): + pass + + +class Client(object): + def __init__(self): + context = zmq.Context() + self.__socket = context.socket(zmq.REQ) + self.__socket.RCVTIMEO = 10000 #ms + self.__socket.setsockopt(zmq.LINGER, 0) + self.__socket.connect(SOCKET_PATH) + + def _communicate(self, msg): + request = json.dumps(msg).encode() + self.__socket.send(request) + + reply_msg = self.__socket.recv().decode() + reply = json.loads(reply_msg) + if 'error' in reply: + raise VyOSHostsdError(reply['error']) + + def set_host_name(self, host_name, domain_name, search_domains): + msg = { + 'type': 'host_name', + 'op': 'set', + 'data': { + 'host_name': host_name, + 'domain_name': domain_name, + 'search_domains': search_domains + } + } + self._communicate(msg) + + def add_hosts(self, tag, hosts): + msg = {'type': 'hosts', 'op': 'add', 'tag': tag, 'data': hosts} + self._communicate(msg) + + def delete_hosts(self, tag): + msg = {'type': 'hosts', 'op': 'delete', 'tag': tag} + self._communicate(msg) + + def add_name_servers(self, tag, servers): + msg = {'type': 'name_servers', 'op': 'add', 'tag': tag, 'data': servers} + self._communicate(msg) + + def delete_name_servers(self, tag): + msg = {'type': 'name_servers', 'op': 'delete', 'tag': tag} + self._communicate(msg) diff --git a/src/services/vyos-hostsd b/src/services/vyos-hostsd new file mode 100755 index 000000000..972c2e3dc --- /dev/null +++ b/src/services/vyos-hostsd @@ -0,0 +1,254 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 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 . +# +# + +import os +import sys +import time +import json +import traceback + +import zmq + +import jinja2 + +debug = True + +DATA_DIR = "/var/lib/vyos/" +STATE_FILE = os.path.join(DATA_DIR, "hostsd.state") + +SOCKET_PATH = "ipc:///run/vyos-hostsd.sock" + +RESOLV_CONF_FILE = '/etc/resolv.conf' +HOSTS_FILE = '/etc/hosts' + +hosts_tmpl_source = """ +### Autogenerated by VyOS ### +127.0.0.1 localhost +127.0.1.1 {{ host_name }}{% if domain_name %}.{{ domain_name }}{% endif %} + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff00::0 ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters + + +{%- if hosts %} +{% for h in hosts -%} +{{hosts[h]['address']}}\t{{h}}\t{% for a in hosts[h]['aliases'] %} {{a}} {% endfor %} +{% endfor %} +{%- endif %} +""" + +hosts_tmpl = jinja2.Template(hosts_tmpl_source) + +resolv_tmpl_source = """ +### Autogenerated by VyOS ### +{% for ns in name_servers -%} +nameserver {{ns}} +{% endfor -%} + +{%- if domain_name %} +domain {{ domain_name }} +{%- endif %} + +{%- if search_domains %} +search {{ search_domains | join(" ") }} +{%- endif %} + +""" + +resolv_tmpl = jinja2.Template(resolv_tmpl_source) + +# The state data includes a list of name servers +# and a list of hosts entries. +# +# Name servers have the following structure: +# {"server": {"tag": }} +# +# Hosts entries are similar: +# {"host": {"tag": , "address": }} +# +# The tag is either "static" or "dhcp-" +# It's used to distinguish entries created +# by different scripts so that they can be removed +# and re-created without having to track what needs +# to be changed +STATE = { + "name_servers": {}, + "hosts": {}, + "host_name": "vyos", + "domain_name": "", + "search_domains": []} + + +def make_resolv_conf(data): + resolv_conf = resolv_tmpl.render(data) + print("Writing /etc/resolv.conf") + with open(RESOLV_CONF_FILE, 'w') as f: + f.write(resolv_conf) + +def make_hosts_file(state): + print("Writing /etc/hosts") + hosts = hosts_tmpl.render(state) + with open(HOSTS_FILE, 'w') as f: + f.write(hosts) + +def add_hosts(data, entries, tag): + hosts = data['hosts'] + + if not entries: + return + + for e in entries: + host = e['host'] + hosts[host] = {} + hosts[host]['tag'] = tag + hosts[host]['address'] = e['address'] + hosts[host]['aliases'] = e['aliases'] + +def delete_hosts(data, tag): + hosts = data['hosts'] + keys_for_deletion = [] + + # You can't delete items from a dict while iterating over it, + # so we build a list of doomed items first + for h in hosts: + if hosts[h]['tag'] == tag: + keys_for_deletion.append(h) + + for k in keys_for_deletion: + del hosts[k] + +def add_name_servers(data, entries, tag): + name_servers = data['name_servers'] + + if not entries: + return + + for e in entries: + name_servers[e] = {} + name_servers[e]['tag'] = tag + +def delete_name_servers(data, tag): + name_servers = data['name_servers'] + keys_for_deletion = [] + + for ns in name_servers: + if name_servers[ns]['tag'] == tag: + keys_for_deletion.append(ns) + + for k in keys_for_deletion: + del name_servers[k] + +def set_host_name(state, data): + if data['host_name']: + state['host_name'] = data['host_name'] + if data['domain_name']: + state['domain_name'] = data['domain_name'] + if data['search_domains']: + state['search_domains'] = data['search_domains'] + +def get_option(msg, key): + if key in msg: + return msg[key] + else: + raise ValueError("Missing required option \"{0}\"".format(key)) + +def handle_message(msg_json): + msg = json.loads(msg_json) + + op = get_option(msg, 'op') + _type = get_option(msg, 'type') + + if op == 'delete': + tag = get_option(msg, 'tag') + + if _type == 'name_servers': + delete_name_servers(STATE, tag) + elif _type == 'hosts': + delete_hosts(STATE, tag) + else: + raise ValueError("Unknown message type {0}".format(_type)) + elif op == 'add': + tag = get_option(msg, 'tag') + entries = get_option(msg, 'data') + if _type == 'name_servers': + add_name_servers(STATE, entries, tag) + elif _type == 'hosts': + add_hosts(STATE, entries, tag) + else: + raise ValueError("Unknown message type {0}".format(_type)) + elif op == 'set': + # Host name/domain name/search domain are set without a tag, + # there can be only one anyway + data = get_option(msg, 'data') + if _type == 'host_name': + set_host_name(STATE, data) + else: + raise ValueError("Unknown message type {0}".format(_type)) + else: + raise ValueError("Unknown operation {0}".format(op)) + + make_resolv_conf(STATE) + make_hosts_file(STATE) + + print("Saving state to {0}".format(STATE_FILE)) + with open(STATE_FILE, 'w') as f: + json.dump(STATE, f) + + +if __name__ == '__main__': + # Create a directory for state checkpoints + os.makedirs(DATA_DIR, exist_ok=True) + if os.path.exists(STATE_FILE): + with open(STATE_FILE, 'r') as f: + try: + data = json.load(f) + STATE = data + except: + print(traceback.format_exc()) + print("Failed to load the state file, using default") + + context = zmq.Context() + socket = context.socket(zmq.REP) + socket.bind(SOCKET_PATH) + + while True: + # Wait for next request from client + message = socket.recv().decode() + print("Received a configuration change request") + if debug: + print("Request data: {0}".format(message)) + + resp = {} + + try: + handle_message(message) + except ValueError as e: + resp['error'] = str(e) + except: + print(traceback.format_exc()) + resp['error'] = "Internal error" + + if debug: + print("Sent response: {0}".format(resp)) + + # Send reply back to client + socket.send(json.dumps(resp).encode()) diff --git a/src/systemd/vyos-hostsd.service b/src/systemd/vyos-hostsd.service new file mode 100644 index 000000000..fe6c163d7 --- /dev/null +++ b/src/systemd/vyos-hostsd.service @@ -0,0 +1,22 @@ +[Unit] +Description=VyOS DNS configuration keeper +After=auditd.service systemd-user-sessions.service time-sync.target + +[Service] +ExecStart=/usr/bin/python3 -u /usr/libexec/vyos/services/vyos-hostsd +Type=idle +KillMode=process + +SyslogIdentifier=vyos-hostsd +SyslogFacility=daemon + +Restart=on-failure + +# Does't work but leave it here +User=root +Group=vyattacfg + +[Install] +# Installing in a earlier target leaves ExecStartPre waiting +WantedBy=getty.target + diff --git a/src/utils/vyos-hostsd-client b/src/utils/vyos-hostsd-client new file mode 100755 index 000000000..d3105c9cf --- /dev/null +++ b/src/utils/vyos-hostsd-client @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 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 . +# +# + +import sys +import argparse + +import vyos.hostsd_client + +parser = argparse.ArgumentParser() +group = parser.add_mutually_exclusive_group() +group.add_argument('--add-hosts', action="store_true") +group.add_argument('--delete-hosts', action="store_true") +group.add_argument('--add-name-servers', action="store_true") +group.add_argument('--delete-name-servers', action="store_true") +group.add_argument('--set-host-name', action="store_true") + +parser.add_argument('--host', type=str, action="append") +parser.add_argument('--name-server', type=str, action="append") +parser.add_argument('--host-name', type=str) +parser.add_argument('--domain-name', type=str) +parser.add_argument('--search-domain', type=str, action="append") + +parser.add_argument('--tag', type=str) + +args = parser.parse_args() + +try: + client = vyos.hostsd_client.Client() + + if args.add_hosts: + if not args.tag: + raise ValueError("Tag is required for this operation") + data = [] + for h in args.host: + entry = {} + params = h.split(",") + if len(params) < 2: + raise ValueError("Malformed host entry") + entry['host'] = params[0] + entry['address'] = params[1] + entry['aliases'] = params[2:] + data.append(entry) + client.add_hosts(args.tag, data) + elif args.delete_hosts: + if not args.tag: + raise ValueError("Tag is required for this operation") + client.delete_hosts(args.tag) + elif args.add_name_servers: + if not args.tag: + raise ValueError("Tag is required for this operation") + client.add_name_servers(args.tag, args.name_server) + elif args.delete_name_servers: + if not args.tag: + raise ValueError("Tag is required for this operation") + client.delete_name_servers(args.tag) + elif args.set_host_name: + client.set_host_name(args.host_name, args.domain_name, args.search_domain) + else: + raise ValueError("Operation required") + +except ValueError as e: + print("Incorrect options: {0}".format(e)) + sys.exit(1) +except vyos.hostsd_client.VyOSHostsdError as e: + print("Server returned an error: {0}".format(e)) + sys.exit(1) + -- cgit v1.2.3 From 6e36bafad6d8300b0bd90261f2a57cf65716ac7f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 26 Aug 2019 22:29:16 +0200 Subject: bridge: T1556: migrate interface configuration to pyroute2 Tested with: set interfaces bridge br0 address '192.0.2.1/24' set interfaces bridge br0 aging '500' set interfaces bridge br0 disable-link-detect set interfaces bridge br0 forwarding-delay '11' set interfaces bridge br0 hello-time '5' set interfaces bridge br0 igmp querier set interfaces bridge br0 max-age '11' set interfaces bridge br0 member interface eth1 cost '1000' set interfaces bridge br0 member interface eth1 priority '4' set interfaces bridge br0 member interface eth2 cost '1001' set interfaces bridge br0 member interface eth2 priority '56' --- debian/control | 1 + src/conf_mode/interface-bridge.py | 238 +++++++++++++++++--------------------- 2 files changed, 109 insertions(+), 130 deletions(-) (limited to 'debian') diff --git a/debian/control b/debian/control index 12eb7c309..7b75ca111 100644 --- a/debian/control +++ b/debian/control @@ -29,6 +29,7 @@ Depends: python3, python3-vici (>= 5.7.2), python3-bottle, python3-zmq, + python3-pyroute2, ipaddrcheck, tcpdump, tshark, diff --git a/src/conf_mode/interface-bridge.py b/src/conf_mode/interface-bridge.py index c5c5bd4ac..d5ef85940 100755 --- a/src/conf_mode/interface-bridge.py +++ b/src/conf_mode/interface-bridge.py @@ -16,13 +16,10 @@ # # -import os -import sys -import copy -import subprocess - -import vyos.configinterface as VyIfconfig - +from os import environ +from copy import deepcopy +from sys import exit +from pyroute2 import IPDB from netifaces import interfaces from vyos.config import Config from vyos import ConfigError @@ -30,44 +27,42 @@ from vyos import ConfigError default_config_data = { 'address': [], 'address_remove': [], - 'aging': '300', - 'arp_cache_timeout_ms': '30000', + 'aging': 300, + 'arp_cache_timeout_ms': 30000, 'description': '', 'deleted': False, - 'dhcp_client_id': '', - 'dhcp_hostname': '', - 'dhcpv6_parameters_only': False, - 'dhcpv6_temporary': False, 'disable': False, - 'disable_link_detect': False, - 'forwarding_delay': '15', - 'hello_time': '2', + 'disable_link_detect': 1, + 'forwarding_delay': 14, + 'hello_time': 2, 'igmp_querier': 0, 'intf': '', 'mac' : '', - 'max_age': '20', + 'max_age': 20, 'member': [], 'member_remove': [], - 'priority': '32768', - 'stp': 'off' + 'priority': 32768, + 'stp': 0 } -def subprocess_cmd(command): - process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True) - proc_stdout = process.communicate()[0].strip() - pass +def freeze(d): + if isinstance(d, dict): + return frozenset((key, freeze(value)) for key, value in d.items()) + elif isinstance(d, list): + return tuple(freeze(value) for value in d) + return d def diff(first, second): second = set(second) return [item for item in first if item not in second] def get_config(): - bridge = copy.deepcopy(default_config_data) + bridge = deepcopy(default_config_data) conf = Config() # determine tagNode instance try: - bridge['intf'] = os.environ['VYOS_TAGNODE_VALUE'] + bridge['intf'] = environ['VYOS_TAGNODE_VALUE'] except KeyError as E: print("Interface not specified") @@ -85,27 +80,13 @@ def get_config(): # retrieve aging - how long addresses are retained if conf.exists('aging'): - bridge['aging'] = conf.return_value('aging') + bridge['aging'] = int(conf.return_value('aging')) # retrieve interface description if conf.exists('description'): bridge['description'] = conf.return_value('description') - - # DHCP client identifier - if conf.exists('dhcp-options client-id'): - bridge['dhcp_client_id'] = conf.return_value('dhcp-options client-id') - - # DHCP client hostname - if conf.exists('dhcp-options host-name'): - bridge['dhcp_hostname'] = conf.return_value('dhcp-options host-name') - - # DHCPv6 acquire only config parameters, no address - if conf.exists('dhcpv6-options parameters-only'): - bridge['dhcpv6_parameters_only'] = True - - # DHCPv6 IPv6 "temporary" address - if conf.exists('dhcpv6-options temporary'): - bridge['dhcpv6_temporary'] = True + else: + bridge['description'] = bridge['intf'] # Disable this bridge interface if conf.exists('disable'): @@ -113,15 +94,15 @@ def get_config(): # Ignore link state changes if conf.exists('disable-link-detect'): - bridge['disable_link_detect'] = True + bridge['disable_link_detect'] = 2 # Forwarding delay if conf.exists('forwarding-delay'): - bridge['forwarding_delay'] = conf.return_value('forwarding-delay') + bridge['forwarding_delay'] = int(conf.return_value('forwarding-delay')) # Hello packet advertisment interval if conf.exists('hello-time'): - bridge['hello_time'] = conf.return_value('hello-time') + bridge['hello_time'] = int(conf.return_value('hello-time')) # Enable Internet Group Management Protocol (IGMP) querier if conf.exists('igmp querier'): @@ -129,8 +110,7 @@ def get_config(): # ARP cache entry timeout in seconds if conf.exists('ip arp-cache-timeout'): - tmp = 1000 * int(conf.return_value('ip arp-cache-timeout')) - bridge['arp_cache_timeout_ms'] = str(tmp) + bridge['arp_cache_timeout_ms'] = int(conf.return_value('ip arp-cache-timeout')) * 1000 # Media Access Control (MAC) address if conf.exists('mac'): @@ -138,21 +118,24 @@ def get_config(): # Interval at which neighbor bridges are removed if conf.exists('max-age'): - bridge['max_age'] = conf.return_value('max-age') + bridge['max_age'] = int(conf.return_value('max-age')) # Determine bridge member interface (currently configured) for intf in conf.list_nodes('member interface'): + # cost and priority initialized with linux defaults + # by reading /sys/devices/virtual/net/br0/brif/eth2/{path_cost,priority} + # after adding interface to bridge after reboot iface = { 'name': intf, - 'cost': '', - 'priority': '' + 'cost': 100, + 'priority': 32 } if conf.exists('member interface {} cost'.format(intf)): - iface['cost'] = conf.return_value('member interface {} cost'.format(intf)) + iface['cost'] = int(conf.return_value('member interface {} cost'.format(intf))) if conf.exists('member interface {} priority'.format(intf)): - iface['priority'] = conf.return_value('member interface {} priority'.format(intf)) + iface['priority'] = int(conf.return_value('member interface {} priority'.format(intf))) bridge['member'].append(iface) @@ -170,11 +153,11 @@ def get_config(): # Priority for this bridge if conf.exists('priority'): - bridge['priority'] = conf.return_value('priority') + bridge['priority'] = int(conf.return_value('priority')) # Enable spanning tree protocol if conf.exists('stp'): - bridge['stp'] = 'on' + bridge['stp'] = 1 return bridge @@ -201,94 +184,89 @@ def generate(bridge): return None def apply(bridge): - cmd = '' - if bridge['deleted']: - # bridges need to be shutdown first - cmd += 'ip link set dev "{}" down'.format(bridge['intf']) - cmd += ' && ' - # delete bridge - cmd += 'brctl delbr "{}"'.format(bridge['intf']) - subprocess_cmd(cmd) + ipdb = IPDB(mode='explicit') + brif = bridge['intf'] + if bridge['deleted']: + try: + # delete bridge interface + with ipdb.interfaces[ brif ] as br: + br.remove() + except: + pass else: - # create bridge if it does not exist - if not os.path.exists("/sys/class/net/" + bridge['intf']): - # create bridge interface - cmd += 'brctl addbr "{}"'.format(bridge['intf']) - cmd += ' && ' - # activate "UP" the interface - cmd += 'ip link set dev "{}" up'.format(bridge['intf']) - cmd += ' && ' - - # set ageing time - cmd += 'brctl setageing "{}" "{}"'.format(bridge['intf'], bridge['aging']) - cmd += ' && ' - - # set bridge forward delay - cmd += 'brctl setfd "{}" "{}"'.format(bridge['intf'], bridge['forwarding_delay']) - cmd += ' && ' - - # set hello time - cmd += 'brctl sethello "{}" "{}"'.format(bridge['intf'], bridge['hello_time']) - cmd += ' && ' - - # set max message age - cmd += 'brctl setmaxage "{}" "{}"'.format(bridge['intf'], bridge['max_age']) - cmd += ' && ' - + try: + # create bridge interface if it not already exists + ipdb.create(kind='bridge', ifname=brif).commit() + except: + pass + + # get handle in bridge interface + br = ipdb.interfaces[brif] + # begin() a transaction prior to make any change + br.begin() + # enable interface + br.up() + # set ageing time - - value is in centiseconds YES! centiseconds! + br.br_ageing_time = bridge['aging'] * 100 + # set bridge forward delay - value is in centiseconds YES! centiseconds! + br.br_forward_delay = bridge['forwarding_delay'] * 100 + # set hello time - value is in centiseconds YES! centiseconds! + br.br_hello_time = bridge['hello_time'] * 100 + # set max message age - value is in centiseconds YES! centiseconds! + br.br_max_age = bridge['max_age'] * 100 # set bridge priority - cmd += 'brctl setbridgeprio "{}" "{}"'.format(bridge['intf'], bridge['priority']) - cmd += ' && ' - + br.br_priority = bridge['priority'] # turn stp on/off - cmd += 'brctl stp "{}" "{}"'.format(bridge['intf'], bridge['stp']) - - for intf in bridge['member_remove']: - # remove interface from bridge - cmd += ' && ' - cmd += 'brctl delif "{}" "{}"'.format(bridge['intf'], intf) - - for intf in bridge['member']: - # add interface to bridge - # but only if it is not yet member of this bridge - if not os.path.exists('/sys/devices/virtual/net/' + bridge['intf'] + '/brif/' + intf['name']): - cmd += ' && ' - cmd += 'brctl addif "{}" "{}"'.format(bridge['intf'], intf['name']) - - # set bridge port cost - if intf['cost']: - cmd += ' && ' - cmd += 'brctl setpathcost "{}" "{}" "{}"'.format(bridge['intf'], intf['name'], intf['cost']) - - # set bridge port priority - if intf['priority']: - cmd += ' && ' - cmd += 'brctl setportprio "{}" "{}" "{}"'.format(bridge['intf'], intf['name'], intf['priority']) - - subprocess_cmd(cmd) + br.br_stp_state = bridge['stp'] + # enable or disable IGMP querier + br.br_mcast_querier = bridge['igmp_querier'] + # update interface description used e.g. within SNMP + br.ifalias = bridge['description'] # Change interface MAC address if bridge['mac']: - VyIfconfig.set_mac_address(bridge['intf'], bridge['mac']) + br.set_address = bridge['mac'] - # update interface description used e.g. within SNMP - VyIfconfig.set_description(bridge['intf'], bridge['description']) - - # Ignore link state changes? - VyIfconfig.set_link_detect(bridge['intf'], bridge['disable_link_detect']) - - # enable or disable IGMP querier - VyIfconfig.set_multicast_querier(bridge['intf'], bridge['igmp_querier']) + # remove interface from bridge + for intf in bridge['member_remove']: + br.del_port( intf['name'] ) - # ARP cache entry timeout in seconds - VyIfconfig.set_arp_cache_timeout(bridge['intf'], bridge['arp_cache_timeout_ms']) + # configure bridge member interfaces + for member in bridge['member']: + # add interface + br.add_port(member['name']) # Configure interface address(es) for addr in bridge['address_remove']: - VyIfconfig.remove_interface_address(bridge['intf'], addr) - + br.del_ip(addr) for addr in bridge['address']: - VyIfconfig.add_interface_address(bridge['intf'], addr) + br.add_ip(addr) + + # up/down interface + if bridge['disable']: + br.down() + + # commit change son bridge interface + br.commit() + + # configure additional bridge member options + for member in bridge['member']: + # configure ARP cache timeout in milliseconds + with open('/proc/sys/net/ipv4/neigh/' + member['name'] + '/base_reachable_time_ms', 'w') as f: + f.write(str(bridge['arp_cache_timeout_ms'])) + # ignore link state changes + with open('/proc/sys/net/ipv4/conf/' + member['name'] + '/link_filter', 'w') as f: + f.write(str(bridge['disable_link_detect'])) + + # adjust member port stp attributes + member_if = ipdb.interfaces[ member['name'] ] + member_if.begin() + # set bridge port cost + member_if.brport_cost = member['cost'] + # set bridge port priority + member_if.brport_priority = member['priority'] + member_if.commit() return None @@ -300,4 +278,4 @@ if __name__ == '__main__': apply(c) except ConfigError as e: print(e) - sys.exit(1) + exit(1) -- cgit v1.2.3 From bfb2b883071b27adbb33035ae51caf69fc338972 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 31 Aug 2019 13:12:04 +0200 Subject: Debian: remove pyroute2 dependency --- debian/control | 1 - 1 file changed, 1 deletion(-) (limited to 'debian') diff --git a/debian/control b/debian/control index 7b75ca111..12eb7c309 100644 --- a/debian/control +++ b/debian/control @@ -29,7 +29,6 @@ Depends: python3, python3-vici (>= 5.7.2), python3-bottle, python3-zmq, - python3-pyroute2, ipaddrcheck, tcpdump, tshark, -- cgit v1.2.3 From 7e367a928505051d8fe05e09a0a284226eb7ecc3 Mon Sep 17 00:00:00 2001 From: Daniil Baturin Date: Wed, 4 Sep 2019 14:59:47 +0200 Subject: T1443: add dependencies on nginx-light and ssl-cert. --- debian/control | 1 + 1 file changed, 1 insertion(+) (limited to 'debian') diff --git a/debian/control b/debian/control index 12eb7c309..dce463157 100644 --- a/debian/control +++ b/debian/control @@ -65,6 +65,7 @@ Depends: python3, mtr-tiny, telnet, traceroute, + ssl-cert, nginx-light, ${shlibs:Depends}, ${misc:Depends} Description: VyOS configuration scripts and data -- cgit v1.2.3