diff options
-rw-r--r-- | interface-definitions/interfaces-bonding.xml | 20 | ||||
-rw-r--r-- | interface-definitions/interfaces-bridge.xml | 5 | ||||
-rw-r--r-- | interface-definitions/interfaces-ethernet.xml | 28 | ||||
-rw-r--r-- | python/vyos/configdict.py | 5 | ||||
-rw-r--r-- | python/vyos/ifconfig.py | 56 | ||||
-rwxr-xr-x | src/conf_mode/interface-bonding.py | 23 | ||||
-rwxr-xr-x | src/conf_mode/interface-bridge.py | 41 | ||||
-rwxr-xr-x | src/conf_mode/interface-ethernet.py | 39 |
8 files changed, 195 insertions, 22 deletions
diff --git a/interface-definitions/interfaces-bonding.xml b/interface-definitions/interfaces-bonding.xml index 88dbab6ab..7279e5993 100644 --- a/interface-definitions/interfaces-bonding.xml +++ b/interface-definitions/interfaces-bonding.xml @@ -101,6 +101,11 @@ <help>DHCP client host name (overrides the system host name)</help> </properties> </leafNode> + <leafNode name="vendor-class-id"> + <properties> + <help>DHCP client vendor type</help> + </properties> + </leafNode> </children> </node> <node name="dhcpv6-options"> @@ -339,6 +344,11 @@ <help>DHCP client host name (overrides the system host name)</help> </properties> </leafNode> + <leafNode name="vendor-class-id"> + <properties> + <help>DHCP client vendor type</help> + </properties> + </leafNode> </children> </node> <node name="dhcpv6-options"> @@ -480,6 +490,11 @@ <help>DHCP client host name (overrides the system host name)</help> </properties> </leafNode> + <leafNode name="vendor-class-id"> + <properties> + <help>DHCP client vendor type</help> + </properties> + </leafNode> </children> </node> <node name="dhcpv6-options"> @@ -605,6 +620,11 @@ <help>DHCP client host name (overrides the system host name)</help> </properties> </leafNode> + <leafNode name="vendor-class-id"> + <properties> + <help>DHCP client vendor type</help> + </properties> + </leafNode> </children> </node> <node name="dhcpv6-options"> diff --git a/interface-definitions/interfaces-bridge.xml b/interface-definitions/interfaces-bridge.xml index 4b82972dc..c026c29b3 100644 --- a/interface-definitions/interfaces-bridge.xml +++ b/interface-definitions/interfaces-bridge.xml @@ -85,6 +85,11 @@ <help>DHCP client host name (overrides the system host name)</help> </properties> </leafNode> + <leafNode name="vendor-class-id"> + <properties> + <help>DHCP client vendor type</help> + </properties> + </leafNode> </children> </node> <node name="dhcpv6-options"> diff --git a/interface-definitions/interfaces-ethernet.xml b/interface-definitions/interfaces-ethernet.xml index e4a56b216..96d2fda10 100644 --- a/interface-definitions/interfaces-ethernet.xml +++ b/interface-definitions/interfaces-ethernet.xml @@ -70,7 +70,12 @@ </leafNode> <leafNode name="host-name"> <properties> - <help>DHCP client host name (overrides the system host name)</help> + <help>DHCP client host name (overrides system host name)</help> + </properties> + </leafNode> + <leafNode name="vendor-class-id"> + <properties> + <help>DHCP client vendor type</help> </properties> </leafNode> </children> @@ -454,7 +459,12 @@ </leafNode> <leafNode name="host-name"> <properties> - <help>DHCP client host name (overrides the system host name)</help> + <help>DHCP client host name (overrides system host name)</help> + </properties> + </leafNode> + <leafNode name="vendor-class-id"> + <properties> + <help>DHCP client vendor type</help> </properties> </leafNode> </children> @@ -615,7 +625,12 @@ </leafNode> <leafNode name="host-name"> <properties> - <help>DHCP client host name (overrides the system host name)</help> + <help>DHCP client host name (overrides system host name)</help> + </properties> + </leafNode> + <leafNode name="vendor-class-id"> + <properties> + <help>DHCP client vendor type</help> </properties> </leafNode> </children> @@ -760,7 +775,12 @@ </leafNode> <leafNode name="host-name"> <properties> - <help>DHCP client host name (overrides the system host name)</help> + <help>DHCP client host name (overrides system host name)</help> + </properties> + </leafNode> + <leafNode name="vendor-class-id"> + <properties> + <help>DHCP client vendor type</help> </properties> </leafNode> </children> diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py index 1c9cf6897..1022b88de 100644 --- a/python/vyos/configdict.py +++ b/python/vyos/configdict.py @@ -112,6 +112,7 @@ def vlan_to_dict(conf): 'description': '', 'dhcp_client_id': '', 'dhcp_hostname': '', + 'dhcp_vendor_class_id': '', 'dhcpv6_prm_only': False, 'dhcpv6_temporary': False, 'disable': False, @@ -145,6 +146,10 @@ def vlan_to_dict(conf): if conf.exists('dhcp-options host-name'): vlan['dhcp_hostname'] = conf.return_value('dhcp-options host-name') + # DHCP client vendor identifier + if conf.exists('dhcp-options vendor-class-id'): + vlan['dhcp_vendor_class_id'] = conf.return_value('dhcp-options vendor-class-id') + # DHCPv6 only acquire config parameters, no address if conf.exists('dhcpv6-options parameters-only'): vlan['dhcpv6_prm_only'] = conf.return_value('dhcpv6-options parameters-only') diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 4ac605b54..23e66c089 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -23,13 +23,26 @@ from netifaces import ifaddresses, AF_INET, AF_INET6 from subprocess import Popen, PIPE, STDOUT from time import sleep +dhclient_base = r'/var/lib/dhcp/dhclient_' dhcp_cfg = """ # generated by ifconfig.py option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; +timeout 60; +retry 300; + interface "{{ intf }}" { send host-name "{{ hostname }}"; - request subnet-mask, broadcast-address, routers, domain-name-servers, rfc3442-classless-static-routes, domain-name, interface-mtu; + {% if client_id -%} + send dhcp-client-identifier "{{ client_id }}"; + {% endif -%} + {% if vendor_class_id -%} + send vendor-class-identifier "{{ vendor_class_id }}"; + {% endif -%} + request subnet-mask, broadcast-address, routers, domain-name-servers, + rfc3442-classless-static-routes, domain-name, interface-mtu; + require subnet-mask; } + """ dhcpv6_cfg = """ @@ -37,10 +50,8 @@ dhcpv6_cfg = """ interface "{{ intf }}" { request routers, domain-name-servers, domain-name; } -""" - -dhclient_base = r'/var/lib/dhcp/dhclient_' +""" class Interface: def __init__(self, ifname, type=None): @@ -78,6 +89,14 @@ class Interface: self._dhcpv6_pid_file = dhclient_base + self._ifname + '.v6pid' self._dhcpv6_lease_file = dhclient_base + self._ifname + '.v6leases' + # DHCP options + self._dhcp_options = { + 'intf' : self._ifname, + 'hostname' : '', + 'client_id' : '', + 'vendor_class_id' : '' + } + def _debug_msg(self, msg): if os.path.isfile('/tmp/vyos.ifconfig.debug'): print('DEBUG/{:<6} {}'.format(self._ifname, msg)) @@ -449,6 +468,21 @@ class Interface: cmd = 'ip addr del "{}" dev "{}"'.format(addr, self._ifname) return self._cmd(cmd) + + def get_dhcp_options(self): + """ + Return dictionary with supported DHCP options. + Dictionary should be altered and send back via set_dhcp_options() + so those options are applied when DHCP is run. + """ + return self._dhcp_options + + def set_dhcp_options(self, options): + """ + Store new DHCP options used by next run of DHCP client. + """ + self._dhcp_options = options + # replace dhcpv4/v6 with systemd.networkd? def _set_dhcp(self): """ @@ -461,15 +495,13 @@ class Interface: >>> j = Interface('eth0') >>> j.set_dhcp() """ - dhcp = { - 'hostname': 'vyos', - 'intf': self._ifname - } - # read configured system hostname. - # maybe change to vyos hostd client ??? - with open('/etc/hostname', 'r') as f: - dhcp['hostname'] = f.read().rstrip('\n') + dhcp = self.get_dhcp_options() + if not dhcp['hostname']: + # read configured system hostname. + # maybe change to vyos hostd client ??? + with open('/etc/hostname', 'r') as f: + dhcp['hostname'] = f.read().rstrip('\n') # render DHCP configuration tmpl = jinja2.Template(dhcp_cfg) diff --git a/src/conf_mode/interface-bonding.py b/src/conf_mode/interface-bonding.py index 4d5009c73..49d2a05d4 100755 --- a/src/conf_mode/interface-bonding.py +++ b/src/conf_mode/interface-bonding.py @@ -34,6 +34,7 @@ default_config_data = { 'deleted': False, 'dhcp_client_id': '', 'dhcp_hostname': '', + 'dhcp_vendor_class_id': '', 'dhcpv6_prm_only': False, 'dhcpv6_temporary': False, 'disable': False, @@ -164,6 +165,10 @@ def get_config(): if conf.exists('dhcp-options host-name'): bond['dhcp_hostname'] = conf.return_value('dhcp-options host-name') + # DHCP client vendor identifier + if conf.exists('dhcp-options vendor-class-id'): + bond['dhcp_vendor_class_id'] = conf.return_value('dhcp-options vendor-class-id') + # DHCPv6 only acquire config parameters, no address if conf.exists('dhcpv6-options parameters-only'): bond['dhcpv6_prm_only'] = conf.return_value('dhcpv6-options parameters-only') @@ -368,9 +373,21 @@ def apply(bond): # update interface description used e.g. within SNMP b.set_alias(bond['description']) - # - # missing DHCP/DHCPv6 options go here - # + # get DHCP config dictionary and update values + opt = b.get_dhcp_options() + + if bond['dhcp_client_id']: + opt['client_id'] = bond['dhcp_client_id'] + + if bond['dhcp_hostname']: + opt['hostname'] = bond['dhcp_hostname'] + + if bond['dhcp_vendor_class_id']: + opt['vendor_class_id'] = bond['dhcp_vendor_class_id'] + + # store DHCP config dictionary - used later on when addresses + # are requested + b.set_dhcp_options(opt) # ignore link state changes b.set_link_detect(bond['disable_link_detect']) diff --git a/src/conf_mode/interface-bridge.py b/src/conf_mode/interface-bridge.py index 37b5c4979..57ac98444 100755 --- a/src/conf_mode/interface-bridge.py +++ b/src/conf_mode/interface-bridge.py @@ -32,6 +32,11 @@ default_config_data = { 'arp_cache_tmo': 30, 'description': '', 'deleted': False, + 'dhcp_client_id': '', + 'dhcp_hostname': '', + 'dhcp_vendor_class_id': '', + 'dhcpv6_prm_only': False, + 'dhcpv6_temporary': False, 'disable': False, 'disable_link_detect': 1, 'forwarding_delay': 14, @@ -81,6 +86,26 @@ def get_config(): if conf.exists('description'): bridge['description'] = conf.return_value('description') + # get DHCP client identifier + if conf.exists('dhcp-options client-id'): + bridge['dhcp_client_id'] = conf.return_value('dhcp-options client-id') + + # DHCP client host name (overrides the system host name) + if conf.exists('dhcp-options host-name'): + bridge['dhcp_hostname'] = conf.return_value('dhcp-options host-name') + + # DHCP client vendor identifier + if conf.exists('dhcp-options vendor-class-id'): + bridge['dhcp_vendor_class_id'] = conf.return_value('dhcp-options vendor-class-id') + + # DHCPv6 only acquire config parameters, no address + if conf.exists('dhcpv6-options parameters-only'): + bridge['dhcpv6_prm_only'] = conf.return_value('dhcpv6-options parameters-only') + + # DHCPv6 temporary IPv6 address + if conf.exists('dhcpv6-options temporary'): + bridge['dhcpv6_temporary'] = conf.return_value('dhcpv6-options temporary') + # Disable this bridge interface if conf.exists('disable'): bridge['disable'] = True @@ -203,6 +228,22 @@ def apply(bridge): # update interface description used e.g. within SNMP br.set_alias(bridge['description']) + # get DHCP config dictionary and update values + opt = br.get_dhcp_options() + + if bridge['dhcp_client_id']: + opt['client_id'] = bridge['dhcp_client_id'] + + if bridge['dhcp_hostname']: + opt['hostname'] = bridge['dhcp_hostname'] + + if bridge['dhcp_vendor_class_id']: + opt['vendor_class_id'] = bridge['dhcp_vendor_class_id'] + + # store DHCP config dictionary - used later on when addresses + # are requested + br.set_dhcp_options(opt) + # Change interface MAC address if bridge['mac']: br.set_mac(bridge['mac']) diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index 317da5772..3cdc03ce5 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -31,6 +31,7 @@ default_config_data = { 'deleted': False, 'dhcp_client_id': '', 'dhcp_hostname': '', + 'dhcp_vendor_class_id': '', 'dhcpv6_prm_only': False, 'dhcpv6_temporary': False, 'disable': False, @@ -66,6 +67,22 @@ def apply_vlan_config(vlan, config): if type(vlan) != type(VLANIf("lo")): raise TypeError() + # get DHCP config dictionary and update values + opt = vlan.get_dhcp_options() + + if config['dhcp_client_id']: + opt['client_id'] = config['dhcp_client_id'] + + if config['dhcp_hostname']: + opt['hostname'] = config['dhcp_hostname'] + + if config['dhcp_vendor_class_id']: + opt['vendor_class_id'] = config['dhcp_vendor_class_id'] + + # store DHCP config dictionary - used later on when addresses + # are requested + vlan.set_dhcp_options(opt) + # update interface description used e.g. within SNMP vlan.set_alias(config['description']) # ignore link state changes @@ -134,6 +151,10 @@ def get_config(): if conf.exists('dhcp-options host-name'): eth['dhcp_hostname'] = conf.return_value('dhcp-options host-name') + # DHCP client vendor identifier + if conf.exists('dhcp-options vendor-class-id'): + eth['dhcp_vendor_class_id'] = conf.return_value('dhcp-options vendor-class-id') + # DHCPv6 only acquire config parameters, no address if conf.exists('dhcpv6-options parameters-only'): eth['dhcpv6_prm_only'] = conf.return_value('dhcpv6-options parameters-only') @@ -273,9 +294,21 @@ def apply(eth): # update interface description used e.g. within SNMP e.set_alias(eth['description']) - # - # missing DHCP/DHCPv6 options go here - # + # get DHCP config dictionary and update values + opt = e.get_dhcp_options() + + if eth['dhcp_client_id']: + opt['client_id'] = eth['dhcp_client_id'] + + if eth['dhcp_hostname']: + opt['hostname'] = eth['dhcp_hostname'] + + if eth['dhcp_vendor_class_id']: + opt['vendor_class_id'] = eth['dhcp_vendor_class_id'] + + # store DHCP config dictionary - used later on when addresses + # are requested + e.set_dhcp_options(opt) # ignore link state changes e.set_link_detect(eth['disable_link_detect']) |