diff --git a/source/topology_plan.py b/source/topology_plan.py index d334149..23a43f2 100644 --- a/source/topology_plan.py +++ b/source/topology_plan.py @@ -43,10 +43,13 @@ class PlannedNode: Args: name: Logical node name used by Mininet. type: Concrete semantic node type to create. + switch_fail_mode: Optional Open vSwitch fail mode selected by the + planner for switch nodes. Non-switch nodes leave this unset. """ name: str type: NodeType + switch_fail_mode: Optional[str] = None @dataclass(frozen=True) @@ -275,7 +278,13 @@ def _plan_nodes(topology: Topology) -> Tuple[PlannedNode, ...]: """ return tuple( - PlannedNode(name=node.name, type=node.type) + PlannedNode( + name=node.name, + type=node.type, + switch_fail_mode=( + "standalone" if node.type is NodeType.SWITCH else None + ), + ) for node in topology.nodes ) @@ -797,6 +806,9 @@ def _self_test() -> None: assert len(execution_plan.nodes) == 3 assert len(execution_plan.links) == 2 + assert next( + node for node in execution_plan.nodes if node.name == "s1" + ).switch_fail_mode == "standalone" assert execution_plan.links[0].endpoints[1].logical_interface == "client" assert execution_plan.links[0].endpoints[0].interface_name == "h1-eth0" assert execution_plan.links[1].endpoints[0].interface_name == "r0-eth0" diff --git a/source/topology_renderer.py b/source/topology_renderer.py index ed78b04..e6cf602 100644 --- a/source/topology_renderer.py +++ b/source/topology_renderer.py @@ -322,10 +322,11 @@ def render_python(plan: ExecutionPlan) -> str: ) elif node.type is NodeType.SWITCH: lines.append( - " nodes[%s] = net.addSwitch(%s)" + " nodes[%s] = net.addSwitch(%s, failMode=%r)" % ( _python_string(node.name), _python_string(node.name), + node.switch_fail_mode, ) ) else: @@ -469,7 +470,7 @@ def _self_test() -> None: ast.parse(source) assert "net.addHost('h1', ip=None)" in source - assert "net.addSwitch('s1')" in source + assert "net.addSwitch('s1', failMode='standalone')" in source assert "net.addLink(" in source assert "cls=TCLink" in source assert "dnsmasq" in source