-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
197 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
# | ||
# First-hop gateway transformation module | ||
# | ||
import typing | ||
from box import Box | ||
import netaddr | ||
|
||
from . import _Module,get_effective_module_attribute | ||
from ..utils import log, strings | ||
from .. import data | ||
from ..augment.nodes import reserve_id | ||
from ..augment import devices | ||
from ..data.validate import validate_attributes,must_be_string | ||
|
||
def check_protocol_support(node: Box, topology: Box) -> bool: | ||
features = devices.get_device_features(node,topology.defaults) | ||
OK = True | ||
|
||
if node.get('dhcp.server',False) and not features.dhcp.server: | ||
log.error( | ||
f'Node {node.name} (device {node.device}) cannot be a DHCP server', | ||
category=log.IncorrectValue, | ||
module='dhcp') | ||
OK = False | ||
|
||
for intf in node.interfaces: | ||
if not intf.get('dhcp.client',False): | ||
continue | ||
for af in ('ipv4','ipv6'): | ||
if not af in intf.dhcp.client: | ||
continue | ||
if not features.dhcp.client[af]: | ||
log.error( | ||
f'Node {node.name} (device {node.device}) does not support {af} DHCP client', | ||
more_data= [ 'DHCP client is used on interface {intf.ifname} ({intf.name})' ], | ||
category=log.IncorrectValue, | ||
module='dhcp') | ||
OK = False | ||
|
||
for intf in node.interfaces: | ||
if not intf.get('dhcp.server',False): | ||
continue | ||
if not features.dhcp.relay: | ||
log.error( | ||
f'Node {node.name} (device {node.device}) cannot be a DHCP relay', | ||
category=log.IncorrectValue, | ||
module='dhcp') | ||
OK = False | ||
|
||
if not topology.nodes.get(f'{intf.dhcp.server}.dhcp.server',False): | ||
log.error( | ||
f'Node {intf.dhcp.server} used for DHCP relaying on node {node.name} is not a DHCP server', | ||
category=log.IncorrectValue, | ||
module='dhcp') | ||
OK = False | ||
|
||
if not intf.get('dhcp.vrf',False): | ||
continue | ||
if not features.dhcp.vrf: | ||
log.error( | ||
f'Node {node.name} (device {node.device}) cannot perform inter-VRF DHCP relaying', | ||
category=log.IncorrectValue, | ||
module='dhcp') | ||
OK = False | ||
|
||
vrf = intf.get('dhcp.vrf') | ||
if vrf == 'global': | ||
continue | ||
|
||
if vrf not in node.get('vrfs',{}): | ||
log.error( | ||
f'VRF {vrf} used for DHCP relaying is not used on node {node.name}', | ||
category=log.IncorrectValue, | ||
module='dhcp') | ||
OK = False | ||
|
||
return OK | ||
|
||
def build_topology_dhcp_pools(topology: Box) -> None: | ||
topology.dhcp.pools = [] | ||
|
||
for link in topology.get('links',[]): | ||
if not link.get('dhcp.subnet'): | ||
continue | ||
|
||
subnet = data.get_empty_box() | ||
|
||
for af in ('ipv4','ipv6'): | ||
if af not in link.dhcp.subnet or af not in link.prefix: | ||
continue | ||
|
||
subnet[af] = link.prefix[af] | ||
subnet.name = link.get('name','') or link.get('_linkname','') | ||
subnet.clean_name = strings.make_id(subnet.name) | ||
|
||
if af in link.get('gateway'): | ||
subnet.gateway[af] = link.gateway[af] | ||
|
||
for intf in link.get('interfaces',[]): | ||
if af not in intf or af in intf.get('dhcp.client',{}): | ||
continue | ||
|
||
if af not in subnet.excluded: | ||
subnet.excluded[af] = [] | ||
|
||
addr = str(netaddr.IPNetwork(intf[af]).ip) | ||
subnet.excluded[af].append(addr) | ||
if af not in subnet.gateway: | ||
subnet.gateway[af] = addr | ||
|
||
topology.dhcp.pools.append(subnet) | ||
|
||
def set_dhcp_server_pools(node: Box, topology: Box) -> None: | ||
if not node.get('dhcp.server',False): | ||
return | ||
|
||
if not topology.get('dhcp.pools',False): | ||
build_topology_dhcp_pools(topology) | ||
|
||
node.dhcp.pools = topology.dhcp.pools | ||
|
||
class DHCP(_Module): | ||
|
||
def link_pre_transform(self, link: Box, topology: Box) -> None: | ||
for intf in link.get('interfaces',[]): | ||
for af in ('ipv4','ipv6'): | ||
if intf.get(af,False) != 'dhcp': | ||
continue | ||
|
||
if not intf.node in topology.nodes: | ||
continue | ||
|
||
intf.pop(af) | ||
intf.dhcp.client[af] = True | ||
link.dhcp.subnet[af] = True | ||
|
||
node = topology.nodes[intf.node] | ||
if 'module' not in node: | ||
node.module = [ 'dhcp' ] | ||
elif 'dhcp' not in node.module: | ||
node.module.append('dhcp') | ||
|
||
def node_post_transform(self, node: Box, topology: Box) -> None: | ||
if not check_protocol_support(node,topology): | ||
return | ||
|
||
for intf in node.get('interfaces',[]): | ||
for af in ('ipv4','ipv6'): | ||
if intf.get(f'dhcp.client.{af}',False): | ||
intf.pop(af,None) | ||
|
||
if node.get('dhcp.server',False): | ||
set_dhcp_server_pools(node,topology) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# DHCP default settings and attributes | ||
# | ||
transform_after: [ vlan, vrf ] | ||
config_after: [ vlan, vrf ] | ||
attributes: | ||
node: | ||
server: bool | ||
interface: | ||
server: node_id | ||
vrf: str | ||
client: | ||
ipv4: bool | ||
ipv6: bool | ||
link: | ||
subnet: | ||
ipv4: bool | ||
ipv6: bool | ||
features: | ||
ipv4: IPv4 DHCP client | ||
ipv6: IPv6 DHCP client | ||
relay: DHCP relay (IPv4 and IPv6) | ||
server: DHCP server | ||
vrf: Inter-VRF DHCP relay |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters