From 02e53c7c540b05c419760427a96afab3ff4d260e Mon Sep 17 00:00:00 2001 From: Ivan Pepelnjak Date: Mon, 6 Mar 2023 18:34:20 +0100 Subject: [PATCH] VRF-aware DHCP relay --- DHCP/vrf-relay/README.md | 13 ++++++++++ DHCP/vrf-relay/dhcp-client/ios.j2 | 5 ++++ DHCP/vrf-relay/dhcp-relay.png | Bin 0 -> 11375 bytes DHCP/vrf-relay/dhcp-relay/eos.j2 | 11 ++++++++ DHCP/vrf-relay/dhcp-relay/ios.j2 | 15 +++++++++++ DHCP/vrf-relay/dhcp-server.j2 | 23 +++++++++++++++++ DHCP/vrf-relay/graph.dot | 21 +++++++++++++++ DHCP/vrf-relay/topology.yml | 41 ++++++++++++++++++++++++++++++ DHCP/vrf-relay/vrf-dhcp-relay.png | Bin 0 -> 12745 bytes 9 files changed, 129 insertions(+) create mode 100644 DHCP/vrf-relay/README.md create mode 100644 DHCP/vrf-relay/dhcp-client/ios.j2 create mode 100644 DHCP/vrf-relay/dhcp-relay.png create mode 100644 DHCP/vrf-relay/dhcp-relay/eos.j2 create mode 100644 DHCP/vrf-relay/dhcp-relay/ios.j2 create mode 100644 DHCP/vrf-relay/dhcp-server.j2 create mode 100644 DHCP/vrf-relay/graph.dot create mode 100644 DHCP/vrf-relay/topology.yml create mode 100644 DHCP/vrf-relay/vrf-dhcp-relay.png diff --git a/DHCP/vrf-relay/README.md b/DHCP/vrf-relay/README.md new file mode 100644 index 0000000..9633a46 --- /dev/null +++ b/DHCP/vrf-relay/README.md @@ -0,0 +1,13 @@ +# VRF-aware DHCP relaying + +This directory contains *netlab* topology file for a simple VRF-aware DHCP relaying scenario. + +![DHCP relaying topology](dhcp-relay.png) + +After starting the lab, the *user* device should get DHCP-assigned IP address on its lab-facing interface. + +## Changing Device Types + +This topology can be used with Cisco IOSv or Arista EOSv. To test it with other devices, add custom configuration template to `dhcp-relay` directory. + +The easiest way to change the device types is to edit the topology file. You could also use the **netlab up** [CLI arguments](https://netsim-tools.readthedocs.io/en/latest/netlab/up.html#usage) -- to change the DHCP relay device type, use `-s nodes.relay.device=xxx` CLI argument. diff --git a/DHCP/vrf-relay/dhcp-client/ios.j2 b/DHCP/vrf-relay/dhcp-client/ios.j2 new file mode 100644 index 0000000..1c868db --- /dev/null +++ b/DHCP/vrf-relay/dhcp-client/ios.j2 @@ -0,0 +1,5 @@ +{% for intf in interfaces if intf.dhcp.client is defined and intf.dhcp.client %} +interface {{ intf.ifname }} + no ip address + ip address dhcp +{% endfor %} \ No newline at end of file diff --git a/DHCP/vrf-relay/dhcp-relay.png b/DHCP/vrf-relay/dhcp-relay.png new file mode 100644 index 0000000000000000000000000000000000000000..be4afd0af0a8b98ce563736bf3c4164d3ac3b221 GIT binary patch literal 11375 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 literal 0 HcmV?d00001 diff --git a/DHCP/vrf-relay/dhcp-relay/eos.j2 b/DHCP/vrf-relay/dhcp-relay/eos.j2 new file mode 100644 index 0000000..4799780 --- /dev/null +++ b/DHCP/vrf-relay/dhcp-relay/eos.j2 @@ -0,0 +1,11 @@ +{% for intf in interfaces if intf.dhcp.server is defined and intf.vrf is defined %} +{% if loop.first %} +ip dhcp relay information option +{% endif %} +{% endfor %} +! +{% for intf in interfaces if intf.dhcp.server is defined %} +{% set helper = hostvars[intf.dhcp.server].loopback.ipv4|ipaddr('address') %} +interface {{ intf.ifname }} + ip helper-address {{ helper }}{% if intf.vrf is defined %} vrf default{% endif %} +{% endfor %} diff --git a/DHCP/vrf-relay/dhcp-relay/ios.j2 b/DHCP/vrf-relay/dhcp-relay/ios.j2 new file mode 100644 index 0000000..8e97426 --- /dev/null +++ b/DHCP/vrf-relay/dhcp-relay/ios.j2 @@ -0,0 +1,15 @@ +{% for intf in interfaces if intf.dhcp.server is defined and intf.vrf is defined %} +{% if loop.first %} +ip dhcp relay information option vpn +{% endif %} +{% endfor %} +! +{% for intf in interfaces if intf.dhcp.server is defined %} +{% set helper = hostvars[intf.dhcp.server].loopback.ipv4|ipaddr('address') %} +interface {{ intf.ifname }} +{% if intf.vrf is defined %} + ip helper-address global {{ helper }} +{% else %} + ip helper-address {{ helper }} +{% endif %} +{% endfor %} \ No newline at end of file diff --git a/DHCP/vrf-relay/dhcp-server.j2 b/DHCP/vrf-relay/dhcp-server.j2 new file mode 100644 index 0000000..5189852 --- /dev/null +++ b/DHCP/vrf-relay/dhcp-server.j2 @@ -0,0 +1,23 @@ +logging buffered +no service timestamp debug +! +do debug ip dhcp server packet +do debug ip dhcp server event +! +{% for h,v in hostvars.items() %} +{% for intf in v.interfaces if intf.dhcp.server is defined and intf.ipv4 is defined %} +ip dhcp excluded-address {% if intf.vrf is defined %}vrf {{ intf.vrf }} {% endif %}{{ intf.ipv4|ipaddr('address') }} +{% endfor %} +{% endfor %} +! +{% for h,v in hostvars.items() %} +{% for intf in v.interfaces if intf.dhcp.server is defined and intf.ipv4 is defined %} +! +ip dhcp pool p_{{ intf.ipv4|ipaddr('network') }} +{% if intf.vrf is defined %} + vrf {{ intf.vrf }} +{% endif %} + network {{ intf.ipv4|ipaddr('network') }} {{ intf.ipv4|ipaddr('netmask') }} + default-router {{ intf.ipv4|ipaddr('address') }} +{% endfor %} +{% endfor %} \ No newline at end of file diff --git a/DHCP/vrf-relay/graph.dot b/DHCP/vrf-relay/graph.dot new file mode 100644 index 0000000..0271fb0 --- /dev/null +++ b/DHCP/vrf-relay/graph.dot @@ -0,0 +1,21 @@ +graph { + bgcolor="transparent" + node [shape=box, style="rounded,filled" fontname=Verdana] + edge [fontname=Verdana labelfontsize=10 labeldistance=1.5] + "srv" [ + label=10.0.0.1/32> + fillcolor="#ff9f01" + ] + "relay" [ + label=10.0.0.2/32> + fillcolor="#ff9f01" + ] + "user" [ + label=10.0.0.3/32> + fillcolor="#ff9f01" + ] + "relay" -- "srv" [ width=5 ] + "relay_2" [style=filled fillcolor="#ff8080" fontsize=11 label=<172.16.0.0/24
VRF client>] + "user" -- "relay_2" [ color="#800000" width=5 ] + "relay" -- "relay_2" [ color="#800000" width=5 ] +} diff --git a/DHCP/vrf-relay/topology.yml b/DHCP/vrf-relay/topology.yml new file mode 100644 index 0000000..ac6ad35 --- /dev/null +++ b/DHCP/vrf-relay/topology.yml @@ -0,0 +1,41 @@ +message: | + This topology sets up a simple network using VRF-aware DHCP relay + functionality. It includes a DHCP server (running on Cisco + IOSv), DHCP client (also on Cisco IOSv) and an intermediate + node. + +defaults.attributes: + link.dhcp: + client: bool + server: str + +defaults.device: iosv + +groups: + dhcp_server: + members: [ srv ] + module: [ ospf ] + config: [ dhcp-server ] + device: csr + dhcp_client: + members: [ user ] + config: [ dhcp-client ] + device: iosv + switch: + members: [ relay ] + module: [ ospf,vrf ] + config: [ dhcp-relay ] + +vrfs: + client: + +nodes: [ srv, relay, user ] + +links: +- relay-srv +- user: + dhcp.client: True + relay: + dhcp.server: srv + type: lan + vrf: client diff --git a/DHCP/vrf-relay/vrf-dhcp-relay.png b/DHCP/vrf-relay/vrf-dhcp-relay.png new file mode 100644 index 0000000000000000000000000000000000000000..326f91c00e5b578b304d6193f9344f0c44abbb81 GIT binary patch literal 12745 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 Mq>@C9m~qJe0(