2019-11-22 20:51:58 +00:00
|
|
|
import logging
|
|
|
|
import random
|
2020-01-14 19:06:52 +00:00
|
|
|
from typing import TYPE_CHECKING, Set, Union
|
2019-10-11 01:02:28 +01:00
|
|
|
|
2019-11-22 20:51:58 +00:00
|
|
|
from netaddr import IPNetwork
|
2019-10-11 01:02:28 +01:00
|
|
|
|
2019-12-19 17:30:21 +00:00
|
|
|
from core.gui.nodeutils import NodeUtils
|
2019-10-22 00:33:18 +01:00
|
|
|
|
2020-01-14 19:06:52 +00:00
|
|
|
if TYPE_CHECKING:
|
|
|
|
from core.gui.app import Application
|
|
|
|
from core.api.grpc import core_pb2
|
|
|
|
from core.gui.graph.node import CanvasNode
|
|
|
|
|
2019-11-22 20:51:58 +00:00
|
|
|
|
|
|
|
def random_mac():
|
|
|
|
return ("{:02x}" * 6).format(*[random.randrange(256) for _ in range(6)])
|
2019-10-22 00:33:18 +01:00
|
|
|
|
|
|
|
|
2020-01-28 18:46:40 +00:00
|
|
|
class Subnets:
|
|
|
|
def __init__(self, ip4: IPNetwork, ip6: IPNetwork) -> None:
|
|
|
|
self.ip4 = ip4
|
|
|
|
self.ip6 = ip6
|
|
|
|
|
|
|
|
def __eq__(self, other: "Subnets") -> bool:
|
|
|
|
return (self.ip4, self.ip6) == (other.ip4, other.ip6)
|
|
|
|
|
|
|
|
def __hash__(self) -> int:
|
|
|
|
return hash((self.ip4, self.ip6))
|
|
|
|
|
|
|
|
def next(self) -> "Subnets":
|
|
|
|
return Subnets(self.ip4.next(), self.ip6.next())
|
|
|
|
|
|
|
|
|
2019-10-11 01:02:28 +01:00
|
|
|
class InterfaceManager:
|
2020-01-28 18:46:40 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
app: "Application",
|
|
|
|
ip4: str = "10.0.0.0",
|
|
|
|
ip4_mask: int = 24,
|
|
|
|
ip6: str = "2001::",
|
|
|
|
ip6_mask=64,
|
|
|
|
) -> None:
|
2019-11-22 20:51:58 +00:00
|
|
|
self.app = app
|
2020-01-28 18:46:40 +00:00
|
|
|
self.ip4_mask = ip4_mask
|
|
|
|
self.ip6_mask = ip6_mask
|
|
|
|
self.ip4_subnets = IPNetwork(f"{ip4}/{ip4_mask}")
|
|
|
|
self.ip6_subnets = IPNetwork(f"{ip6}/{ip6_mask}")
|
|
|
|
self.current_subnets = None
|
2019-11-25 19:31:40 +00:00
|
|
|
|
2020-01-28 18:46:40 +00:00
|
|
|
def next_subnets(self) -> Subnets:
|
2019-11-25 19:31:40 +00:00
|
|
|
# define currently used subnets
|
|
|
|
used_subnets = set()
|
2019-12-19 19:10:08 +00:00
|
|
|
for edge in self.app.core.links.values():
|
|
|
|
link = edge.link
|
2020-01-28 18:46:40 +00:00
|
|
|
subnets = None
|
2019-11-25 19:31:40 +00:00
|
|
|
if link.HasField("interface_one"):
|
2020-01-28 18:46:40 +00:00
|
|
|
subnets = self.get_subnets(link.interface_one)
|
2019-11-25 19:31:40 +00:00
|
|
|
if link.HasField("interface_two"):
|
2020-01-28 18:46:40 +00:00
|
|
|
subnets = self.get_subnets(link.interface_two)
|
|
|
|
if subnets:
|
|
|
|
used_subnets.add(subnets)
|
2019-11-25 19:31:40 +00:00
|
|
|
|
2020-01-28 18:46:40 +00:00
|
|
|
# find next available subnets
|
|
|
|
subnets = Subnets(self.ip4_subnets, self.ip6_subnets)
|
|
|
|
while subnets in used_subnets:
|
|
|
|
subnets = subnets.next()
|
|
|
|
return subnets
|
2019-11-22 20:51:58 +00:00
|
|
|
|
2019-11-22 22:58:41 +00:00
|
|
|
def reset(self):
|
2020-01-28 18:46:40 +00:00
|
|
|
self.current_subnets = None
|
2019-11-22 22:58:41 +00:00
|
|
|
|
2020-01-28 18:46:40 +00:00
|
|
|
def get_ips(self, node_id: int) -> [str, str]:
|
|
|
|
ip4 = self.current_subnets.ip4[node_id]
|
|
|
|
ip6 = self.current_subnets.ip6[node_id]
|
|
|
|
return str(ip4), str(ip6)
|
2019-11-22 20:51:58 +00:00
|
|
|
|
2019-11-23 07:48:10 +00:00
|
|
|
@classmethod
|
2020-01-28 18:46:40 +00:00
|
|
|
def get_subnets(cls, interface: "core_pb2.Interface") -> Subnets:
|
|
|
|
ip4_subnet = IPNetwork(f"{interface.ip4}/{interface.ip4mask}").cidr
|
|
|
|
ip6_subnet = IPNetwork(f"{interface.ip6}/{interface.ip6mask}").cidr
|
|
|
|
return Subnets(ip4_subnet, ip6_subnet)
|
2019-11-23 00:30:25 +00:00
|
|
|
|
2020-01-28 18:46:40 +00:00
|
|
|
def determine_subnets(
|
2020-01-14 19:06:52 +00:00
|
|
|
self, canvas_src_node: "CanvasNode", canvas_dst_node: "CanvasNode"
|
2020-01-13 20:03:13 +00:00
|
|
|
):
|
2019-11-22 20:51:58 +00:00
|
|
|
src_node = canvas_src_node.core_node
|
|
|
|
dst_node = canvas_dst_node.core_node
|
|
|
|
is_src_container = NodeUtils.is_container_node(src_node.type)
|
|
|
|
is_dst_container = NodeUtils.is_container_node(dst_node.type)
|
|
|
|
if is_src_container and is_dst_container:
|
2020-01-28 18:46:40 +00:00
|
|
|
self.current_subnets = self.next_subnets()
|
2019-11-22 20:51:58 +00:00
|
|
|
elif is_src_container and not is_dst_container:
|
2020-01-28 18:46:40 +00:00
|
|
|
subnets = self.find_subnets(canvas_dst_node, visited={src_node.id})
|
|
|
|
if subnets:
|
|
|
|
self.current_subnets = subnets
|
2019-11-22 20:51:58 +00:00
|
|
|
else:
|
2020-01-28 18:46:40 +00:00
|
|
|
self.current_subnets = self.next_subnets()
|
2019-11-22 20:51:58 +00:00
|
|
|
elif not is_src_container and is_dst_container:
|
2020-01-28 18:46:40 +00:00
|
|
|
subnets = self.find_subnets(canvas_src_node, visited={dst_node.id})
|
|
|
|
if subnets:
|
|
|
|
self.current_subnets = subnets
|
2019-11-22 20:51:58 +00:00
|
|
|
else:
|
2020-01-28 18:46:40 +00:00
|
|
|
self.current_subnets = self.next_subnets()
|
2019-11-22 20:51:58 +00:00
|
|
|
else:
|
|
|
|
logging.info("ignoring subnet change for link between network nodes")
|
|
|
|
|
2020-01-28 18:46:40 +00:00
|
|
|
def find_subnets(
|
2020-01-14 19:06:52 +00:00
|
|
|
self, canvas_node: "CanvasNode", visited: Set[int] = None
|
|
|
|
) -> Union[IPNetwork, None]:
|
2019-11-22 20:51:58 +00:00
|
|
|
logging.info("finding subnet for node: %s", canvas_node.core_node.name)
|
|
|
|
canvas = self.app.canvas
|
2020-01-28 18:46:40 +00:00
|
|
|
subnets = None
|
2019-11-23 07:48:10 +00:00
|
|
|
if not visited:
|
|
|
|
visited = set()
|
2019-11-22 20:51:58 +00:00
|
|
|
visited.add(canvas_node.core_node.id)
|
|
|
|
for edge in canvas_node.edges:
|
|
|
|
src_node = canvas.nodes[edge.src]
|
|
|
|
dst_node = canvas.nodes[edge.dst]
|
|
|
|
interface = edge.src_interface
|
|
|
|
check_node = src_node
|
|
|
|
if src_node == canvas_node:
|
|
|
|
interface = edge.dst_interface
|
|
|
|
check_node = dst_node
|
|
|
|
if check_node.core_node.id in visited:
|
|
|
|
continue
|
|
|
|
visited.add(check_node.core_node.id)
|
|
|
|
if interface:
|
2020-01-28 18:46:40 +00:00
|
|
|
subnets = self.get_subnets(interface)
|
2019-11-22 20:51:58 +00:00
|
|
|
else:
|
2020-01-28 18:46:40 +00:00
|
|
|
subnets = self.find_subnets(check_node, visited)
|
|
|
|
if subnets:
|
|
|
|
logging.info("found subnets: %s", subnets)
|
2019-11-23 07:48:10 +00:00
|
|
|
break
|
2020-01-28 18:46:40 +00:00
|
|
|
return subnets
|