Another day – another “Certification”

I just got my newest “Certification” – and nope – it’s indeed a non-Juniper one πŸ˜€

Berechtigung nach Β§ 21 Absatz 5 Satz 1
Krankenhausstrukturfonds-Verordnung (KHSFV)

That one is needed if you want to work with the hospitality and medical sector when working with funds that can be accessed to help digitalize the hospitals / medical systems.

Much needed here in Germany as most of the systems are still, let’s say, “stoneage” or software-islands without any interoperability or defined standards – Germany is a bit slower when it comes to digitalization (after all, the Internet is new to us – germans get this joke).

The test validates your understanding of all parts of the funding and also basically verifies that you know, what you are doing from accessing funds, it-security, how the systems and parts need to be interoperable, and so on πŸ˜‰

EVE-NG 4.0.1-15-Cluster released – All the Lab Graphs in the world

ICYMI – EVE-NG just released the latest version of the EVE-Cluster (4.0.1-15). This version brings some more nice gadgets to play with: Traffic-Graphs πŸ™‚

4.0.1-15 brings graphs to your Lab environment

This is a convenient and interesting feature when dealing with all kinds of generated Traffic in and out of your Lab, between nodes, or between “helper-nodes” and your Lab. If you don’t want to fire up Wireshark to see if Traffic is really flowing, you can now easily use the graphs. This is currently a “Pro-Only” feature and another good reason to switch to EVE-NG Pro πŸ™‚ As you can see, the Team is constantly evolving the software more and more – and every time you think that this is the perfect release – the Team surprises us again πŸ™‚ As always – great Job / Tippin my Fedora πŸ˜‰

EVE-NG Pro 4.0: Brace yourselves – CLUSTER is coming…

Did it really happen? Hell yeah – it finally happened πŸ™‚
One of the most requested features of all time is coming to life – and boy is it fun πŸ™‚

I had the honor of trying it a few days before the release, and I’m impressed with how good it works considering this is an FRS – which makes it even more amazing. With the Cluster update, new possibilities arise. You can now scale your Labs even more, and the best part is: you don’t even need to worry about images on the satellites. But wait – what’s a satellite? Let me show you.

EVE-NG is (considering it’s a Standalone-Server) a “master” Server. This means that you login to this server and use it to manage your Topology. If you want to add more Resources (additional Servers), they are considered “satellites” – they provide the needed horsepower for your master to run additional nodes. In most systems, you need to do the “imaging” yourself – meaning that for every node that you want to start, the image needs to be present on the satellite (since it obviously needs the harddisk file). With EVE this is different – you simply select the satellite that your node should run on, and EVE takes care of the image distribution – how awesome is that???

What about updates, you ask? Well – the EVE team has got you covered πŸ˜‰ You just update your master, and the master will push the agent update to your satellite and update it – while you sip a coffee or do other tasks. While the GNS3 folks update all the servers, you can enjoy time with the family πŸ˜›

NoHate I’m sure the GNS folks will forgive me for this πŸ˜‰

And do you know the best part? You don’t need to pay for a Cluster-License. That’s right – all the sweet awesomeness of EVE-Clustering at the cost of the Pro-Edition. When I heard about this, I was EXTREMELY grateful – now your only limit is your budget for new Servers, but since that is infinite, you can scale your labs to new heights πŸ™‚

What? You want to know how the communication between the master and the satellite works? Alright:

EVE communicates over vxlan between the satellites and the master. And if this wasn’t cool enough for you: What if I told you that EVE uses wireguard (yes, you read correctly) to secure the connections. Every console session, every ssh-connection, every network you create between the master and the sat – no one will be able to sniff the good stuff you have created. Awesome, right? I have never seen anything like this before – most Vendors give a shit about security and the EVE-Team just showed us all how it’s done!


Congrats to the Team for this really awesome release!

I will cover the Clusterfeatures in my next talk at the Juniper Open-Learning Series
(Tuesday, March 2, 2021 7:00 AM PST):
https://learningportal.juniper.net/juniper/user_activity_schedule_info.aspx?id=161880&activity=11495
Make sure to register your seat early πŸ™‚ There might even be a prize to win this time πŸ˜‰

EVE-NG Pro 3.0.1-17 update is out

The EVE-NG Team just released the latest Update for the Pro Edition.

  • New templates for Catalyst 8000, FreeNAS, Android, and many more
  • Template updates
  • Node icons library

The update also fixed a “security flaw” in guacamole, where the guacadmin password was still set to “guacadmin.” Apparently, not many users were aware of that, and some even put the EVE straight into the www instead of having a decent firewall between the EVE and the www.

Seriously, guys – it’s 2021 – this should not even be a concern.
Exposing a Solution to the www without changing every tiny setting and password is like crying out loud, “hack me fast plz” – this happens automated nowadays, by the way!

My advice is always to have a decent Firewall between you (somewhere in the www) and your Lab.
Use a VPN to connect to it, and you are safe!

And to all the Users out there calling it a “backdoor” or “hack of the century”:


I suggest you first learn what a backdoor is and then start flaming πŸ˜‰
May I recommend https://en.wikipedia.org/wiki/Backdoor_(computing)?
If you are lazy, here’s a summary: Backdoor means bypassing normal authentication or encryption – this was never the case here. It was just a default user that allowed this – nothing fancy… This user’s password is “scrambled” now, so you don’t need to cry anymore…
Shoutouts to the copycats from pnetlab who tried so hard to throw some dirt πŸ˜‰

If you use IPv6 only (like me), make sure to change the ovfstartup script (opt/ovf/ovfstartup.sh) after the update so that your Server is reachable via v6 again:

#Disable ipv6 on EVE Host
grep -q 'ipv6.*0' /opt/unetlab/html/includes/config.yml 2>/dev/null && sysctl -w net.ipv6.conf.all.disable_ipv6=1
grep -q 'ipv6 ' /opt/unetlab/html/includes/config.yml 2>/dev/null || sysctl -w net.ipv6.conf.all.disable_ipv6=1
<strong>grep -q 'ipv6.*1' /opt/unetlab/html/includes/config.yml 2>/dev/null && sysctl -w net.ipv6.conf.all.disable_ipv6=0</strong>

The last line is important – save the changes and reboot your server.
Your IPv6 should be reachable again πŸ™‚
That’s all I have for you today – stay safe, folks!

vQFX and vMX custom Icons for EVE-NG

Nothing beats a stunning Topology in EVE-NG so I attached you the images that I use for the vQFX and vMX RE. I’m still creating a nice PFE image and of course the vSRX image – that follows here later πŸ™‚

Enjoy

Juniper Open Learning: Using EVE-NG with Juniper Topologies – Slides

Since so many of you asked for it: Of course I can share the Slides πŸ™‚

Here you find the Slides from the Session held on 15.09.2020

Adding IPv6 to your PfSense OpenVPN to access IPv6 content in IPv4-only networks

Yesterday I played with the OpenVPN Settings in my PfSense at home and thought:
Will it be possible to enable IPv6 through my VPN so that I can access my IPv6 only Content even when I’m staying at my parents-in-law where I only have a crappy 1&1 IPv4 DSL?
Turns out: HELL YEAH πŸ˜€

This was way easier than I thought, but I thought I share it with you.
This article is based on the following assumptions:
– You already have your OpenVPN running over IPv4
– Your Server has connection over IPv4 and IPv6 (basically, you are dual-homed so that the Server can access the content and serve it to you)
– You have a free /64 Subnet for your clients to use that is routed towards your Server’s GW IP

Start by navigating to VPN –> OpenVPN. Next to the “Server,” hit the Edit button.
You should now see a similar screen to the one below:

You can leave the Protocol to IPv4 only. I want my Clients to have IPv6 Access everywhere. Enabling the Protocol for both IP-Families does not make sense to me. If I have v6 connectivity already, I can surf away – this only makes sense if you also want to connect via IPv6 in IPv6-only networks but still get your IPv6 Prefix due to ACLs and such.

If you scroll down, you see the IPv6-Tunnel-Network. Insert your /64 prefix in there. PfSense will take care of the Rest for you (DHCPv6, Gateway creation, and so on) so that your clients know how to reach the IPv6 World and get an IPv6 address from your subnet. I also ticked “force all Traffic through the tunnel.” If you don’t check this box, your Client will get an IPv6 Address assigned and will then try to talk IPv6 directly (which will fail in IPv4-only networks obviously) to the resources out there.

You want to make sure, that your Clients are able to resolve IPv6 FQDN’s so don’t forget to add at least one IPv6 Nameserver IP to your DNS Section of the Settings.

If you scroll down a little further, you will see the “Gateway creation” section. Initially, mine was set to IPv4 only – change this to “Both” so that PfSense automatically creates the Gateways for you. You can do that manually, but why make life harder than it needs to be? IPv6 is straightforward – and we should leave it this way πŸ™‚

Hit the “Safe” Button and that’s basically it.

At least I thought… πŸ˜‰

Remember: You just enabled IPv6 for your Tunnel, but your Client is still using the old config-file for IPv4 only!
So either go to the “Client Export” Section and download the new config file or add this to your current config:

tun-ipv6

I added it just below the IPv4 tun mode so my file begins with:

dev tun<br>tun-ipv6<br>...<br>...<br>...

That’s it. Connect to your Server again and BAM – IPv6 tunneled through IPv4 πŸ™‚
Hope this helps you to enjoy IPv6 everywhere!

Juniper Open Learning: Technical Series Using EVE-NG with Juniper Topologies

On September 15th 2020 I will host another session with the amazing @JuniperCertify team about EVE-NG and Juniper devices.
Reserve your seat here: https://learningportal.juniper.net/juniper/user_activity_schedule_info.aspx?id=157373&activity=11495

Topics are:
EVE-NG in IPv6-only mode
Creating Custom Templates (vSRX 3.0, JunOS Space Policy Enforcer, etc.) [Live-Demo]
Tips, tricks, and new features [Live-Demo]
Questions and Answers

Whether you are new to Juniper and EVE-NG or already a veteran – I’m sure you will learn something in the session πŸ™‚ If you have questions, feel free bring them to the session.

Looking forward to a great session with the most amazing community πŸ™‚

Create a config export script for the vSRX 3.0 template

Some time ago I blogged about a custom template for the vSRX 3.0. One drawback was, that the config-export would no longer work, since this is a custom template but I took this drawback because the speed improvements were very good and I usually export my config manually. But I understand, that some of you use this feature in and out so I tried to generate a config-export-script. With the help of Alain from EVE-NG I was able to map the config-script to the new template πŸ™‚ Huge thanks to Alain πŸ™‚

Here’s what you need to do:

1.) Copy this script with the name config_vsrx30.py to /opt/unetlab/scripts/ – here’s my script, that will use the username ‘root’ and the password ‘Juniper’:

#!/usr/bin/env python3

# scripts/config_vsrx30.py
#
# Import/Export script for vsrx30.
#
# @author Andrea Dainese <andrea.dainese@gmail.com>
# @author Alain Degreffe <eczema@ecze.com>
# @copyright 2014-2016 Andrea Dainese
# @copyright 2017-2018 Alain Degreffe
# @copyright 2019-2020 Christian Scholz
# @license BSD-3-Clause https://github.com/dainok/unetlab/blob/master/LICENSE
# @link http://www.eve-ng.net/
# @version 20200422

import getopt, multiprocessing, os, pexpect, re, sys, time

username = 'root'
password = 'Juniper'
conntimeout = 3     # Maximum time for console connection
expctimeout = 3     # Maximum time for each short expect
longtimeout = 30    # Maximum time for each long expect
timeout = 60        # Maximum run time (conntimeout is included)

def node_login(handler):
    # Send an empty line, and wait for the login prompt
    i = -1
    while i == -1:
        try:
            handler.sendline('\r\n')
            i = handler.expect([
                'login:',
                'root@.*%',
                'root>',
                'root@.*>',
                'root#',
                'root@.*#'], timeout = 5)
        except:
            i = -1

    if i == 0:
        # Need to send username and password
        handler.sendline(username)
        try:
            j = handler.expect(['root@.*#', 'Password:'], timeout = longtimeout)
        except:
            print('ERROR: error waiting for ["root@.*%", "password:"] prompt.')
            node_quit(handler)
            return False

        if j == 0:
            # Nothing to do
            return True
        elif j == 1:
            handler.sendline(password)
            try:
                handler.expect('root@.*#', timeout = longtimeout)
            except:
                print('ERROR: error waiting for "root@.*%" prompt.')
                node_quit(handler)
                return False
            return True
        else:
            # Unexpected output
            node_quit(handler)
            return False
    elif i == 1:
        # Nothing to do
        return True
    elif i == 2 or i == 3:
        # Exit from CLI mode
        handler.sendline('exit')
        try:
            handler.expect('root@.*%', timeout = expctimeout)
        except:
            print('ERROR: error waiting for "root@.*%" prompt.')
            node_quit(handler)
            return False
        return True
    elif i == 4:
        # Exit from configuration mode
        handler.sendline('exit')
        try:
            handler.expect(['root>', 'root@.*>'], timeout = expctimeout)
        except:
            print('ERROR: error waiting for ["root>", "root@.*>"] prompt.')
            node_quit(handler)
            return False
        # Exit from CLI mode
        handler.sendline('exit')
        try:
            handler.expect('root.*%', timeout = expctimeout)
        except:
            print('ERROR: error waiting for "root@.*%" prompt.')
            node_quit(handler)
            return False
        return True
    elif i == 5:
        return True
    else:
        # Unexpected output
        node_quit(handler)
        return False

def node_quit(handler):
    if handler.isalive() == True:
        handler.sendline('exit\n')
    handler.close()

def config_get(handler):
    # Clearing all "expect" buffer
    while True:
        try:
            handler.expect('root@.*#', timeout = 0.1)
        except:
            break

    # Go into CLI mode
    handler.sendline('cli')
    try:
        handler.expect(['root>', 'root@.*>'], timeout = longtimeout)
    except:
        print('ERROR: error waiting for ["root>", "root@.*>"] prompt.')
        node_quit(handler)
        return False

    # Disable paging
    handler.sendline('set cli screen-length 0')
    try:
        handler.expect(['root>', 'root@.*>'], timeout = longtimeout)
    except:
        print('ERROR: error waiting for ["root>", "root@.*>"] prompt.')
        node_quit(handler)
        return False

    # Getting the config
    handler.sendline('show configuration | display set')
    try:
        handler.expect(['root>', 'root@.*>'], timeout = longtimeout)
    except:
        print('ERROR: error waiting for ["root>", "root@.*>"] prompt.')
        node_quit(handler)
        return False

    config = handler.before.decode()

    # Exit from config mode
    handler.sendline('exit')
    try:
        handler.expect('root@.*#', timeout = longtimeout)
    except:
        print('ERROR: error waiting for "root@.*%" prompt.')
        node_quit(handler)
        return False
    
    # Manipulating the config
    config = re.sub('\r', '', config, flags=re.DOTALL)                                      # Unix style
    config = re.sub('.*show configuration \| display set', '', config, flags=re.DOTALL)          # Header
    config = re.sub('\nroot.*>.*', '\n', config, flags=re.DOTALL)                        # Footer

    return config

def config_put(handler, config):
    # mount drive
    handler.sendline('mount -t cd9660 /dev/cd0 /mnt')
    try:
        handler.expect(['root>', 'root@.*#'], timeout = expctimeout)
    except:
        print('ERROR: error waiting for ["root>", "root@.*%"] prompt.')
        node_quit(handler)
        return False

    # Go into CLI mode
    handler.sendline('cli')
    try:
        handler.expect(['root>', 'root@.*>'], timeout = longtimeout)
    except:
        print('ERROR: error waiting for ["root>", "root@.*>"] prompt.')
        node_quit(handler)
        return False

    # Got to configure mode
    handler.sendline('configure')
    try:
        handler.expect(['root#', 'root@.*#'], timeout = longtimeout)
    except:
        print('ERROR: error waiting for ["root#", "root@.*#"] prompt.')
        node_quit(handler)
        return False

    # Start the load mode
    handler.sendline('load set /mnt/juniper.conf')
    try:
        handler.expect('load complete', timeout = longtimeout)
    except:
        print('ERROR: error waiting for "load complete" prompt.')
        node_quit(handler)
        return False

    # Save
    handler.sendline('commit')
    try:
        handler.expect(['root#', 'root@.*#'], timeout = longtimeout)
    except:
        print('ERROR: error waiting for ["root#", "root@.*#"] prompt.')
        node_quit(handler)
        return False

    handler.sendline('exit')
    try:
        handler.expect(['root>', 'root@.*>'], timeout = longtimeout)
    except:
        print('ERROR: error waiting for ["root>", "root@.*>"] prompt.')
        node_quit(handler)
        return False

    return True

def usage():
    print('Usage: %s <standard options>' %(sys.argv[0]));
    print('Standard Options:');
    print('-a <s>    *Action can be:')
    print('           - get: get the startup-configuration and push it to a file')
    print('           - put: put the file as startup-configuration')
    print('-f <s>    *File');
    print('-p <n>    *Console port');
    print('-t <n>     Timeout (default = %i)' %(timeout));
    print('* Mandatory option')

def now():
    # Return current UNIX time in milliseconds
    return int(round(time.time() * 1000))

def main(action, fiename, port):
    try:
        # Connect to the device
        tmp = conntimeout
        while (tmp > 0):
            handler = pexpect.spawn('telnet 127.0.0.1 %i' %(port))
            time.sleep(0.1)
            tmp = tmp - 0.1
            if handler.isalive() == True:
                break

        if (handler.isalive() != True):
            print('ERROR: cannot connect to port "%i".' %(port))
            node_quit(handler)
            sys.exit(1)

        # Login to the device and get a privileged prompt
        rc = node_login(handler)
        if rc != True:
            print('ERROR: failed to login.')
            node_quit(handler)
            sys.exit(1)

        if action == 'get':
            config = config_get(handler)
            if config in [False, None]:
                print('ERROR: failed to retrieve config.')
                node_quit(handler)
                sys.exit(1)

            try:
                fd = open(filename, 'a')
                fd.write(config)
                fd.close()
            except:
                print('ERROR: cannot write config to file.')
                node_quit(handler)
                sys.exit(1)
        elif action == 'put':
            try:
                fd = open(filename, 'r')
                config = fd.read()
                fd.close()
            except:
                print('ERROR: cannot read config from file.')
                node_quit(handler)
                sys.exit(1)

            rc = config_put(handler, config)
            if rc != True:
                print('ERROR: failed to push config.')
                node_quit(handler)
                sys.exit(1)

            # Remove lock file
            lock = '%s/.lock' %(os.path.dirname(filename))

            if os.path.exists(lock):
                os.remove(lock)

            # Mark as configured
            configured = '%s/.configured' %(os.path.dirname(filename))
            if not os.path.exists(configured):
                open(configured, 'a').close()

        node_quit(handler)
        sys.exit(0)

    except Exception as e:
        print('ERROR: got an exception')
        print(type(e))  # the exception instance
        print(e.args)   # arguments stored in .args
        print(e)        # __str__ allows args to be printed directly,
        node_quit(handler)
        return False

if __name__ == "__main__":
    action = None
    filename = None
    port = None

    # Getting parameters from command line
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'a:p:t:f:', ['action=', 'port=', 'timeout=', 'file='])
    except getopt.GetoptError as e:
        usage()
        sys.exit(3)

    for o, a in opts:
        if o in ('-a', '--action'):
            action = a
        elif o in ('-f', '--file'):
            filename = a
        elif o in ('-p', '--port'):
            try:
                port = int(a)
            except:
                port = -1
        elif o in ('-t', '--timeout'):
            try:
                timeout = int(a) * 1000
            except:
                timeout = -1
        else:
            print('ERROR: invalid parameter.')

    # Checking mandatory parameters
    if action == None or port == None or filename == None:
        usage()
        print('ERROR: missing mandatory parameters.')
        sys.exit(1)
    if action not in ['get', 'put']:
        usage()
        print('ERROR: invalid action.')
        sys.exit(1)
    if timeout < 0:
        usage()
        print('ERROR: timeout must be 0 or higher.')
        sys.exit(1)
    if port < 0:
        usage()
        print('ERROR: port must be 32768 or higher.')
        sys.exit(1)
    if action == 'get' and os.path.exists(filename):
        usage()
        print('ERROR: destination file already exists.')
        sys.exit(1)
    if action == 'put' and not os.path.exists(filename):
        usage()
        print('ERROR: source file does not already exist.')
        sys.exit(1)
    if action == 'put':
        try:
            fd = open(filename, 'r')
            config = fd.read()
            fd.close()
        except:
            usage()
            print('ERROR: cannot read from file.')
            sys.exit(1)

    # Backgrounding the script
    end_before = now() + timeout
    p = multiprocessing.Process(target=main, name="Main", args=(action, filename, port))
    p.start()

    while (p.is_alive() and now() < end_before):
        # Waiting for the child process to end
        time.sleep(1)

    if p.is_alive():
        # Timeout occurred
        print('ERROR: timeout occurred.')
        p.terminate()
        sys.exit(127)

    if p.exitcode != 0:
        sys.exit(127)

    sys.exit(0)

Now that we have our python script under /opt/unetlab/scripts/config_vsrx30.py we need to add a line to our vSRX 3.0 template located at /opt/unetlab/html/templates/intel/vsrx30.yml

# Copyright (c) 2016, Andrea Dainese
# Copyright (c) 2016, Alain Degreffe
# Copyright (c) 2017, Alain Degreffe
# Copyright (c) 2019, Christian Scholz
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#     * Neither the name of the UNetLab Ltd nor  the name of EVE-NG Ltd nor the
#       names of its contributors may be used to endorse or promote products
#       derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
type: qemu
name: vSRX3-0
config_script: config_vsrx30.py
cpulimit: 1
icon: JuniperSRX.png
cpu: 2
ram: 4096
eth_name:
- fxp0/mgmt
eth_format: ge-0/0/{0}
ethernet: 6
qemu_nic: virtio-net-pci
console: telnet
qemu_arch: x86_64
qemu_options: -machine type=pc-1.0,accel=kvm -cpu qemu64,+ssse3,+sse4.1,+sse4.2,+x2apic,+aes,pclmulqdq  -serial
  mon:stdio -nographic   -nodefconfig -nodefaults -rtc base=utc
...

As you can see, the line “config_script: config_vsrx30.py” has been added, so that the server knows, what script to trigger when using the vSRX3.0 template. After I added this line and saved it, I could immediately export without having to reboot the server or wipe a device πŸ™‚

As you can see, it’s now possible to export your vSRX3.0 configs even with the custom template πŸ™‚ Enjoy!

Keeping the Network Up and Running During the COVID-19 Era (A Virtual Panel with Networking Experts)

Last week I blogged about the virtual Roundtable that we had to discuss our work in the Corona Era.

I promised you to share this exciting talk – huge shoutouts to the Team and to Mike for hosting us – this was one of the best sessions we did so far and I enjoyed it a lot πŸ™‚ Below you find the description and the Video:

The COVID-19 pandemic is putting unprecedented strain on not only our way of living but our networks as well. Juniper Networks’ CMO, Mike Marcellin, and networking experts from several Juniper customers and partners recently met to discuss what they’re experiencing on the front lines of IT and share advice as we navigate the path forward. For more advice and discussions with our IT community, please visit Real Talk: The Network Matters, a forum dedicated to sharing advice, strategies and workarounds that everyone can use: https://forums.juniper.net/t5/Real-Ta…

And a big thank you to our panel of experts:
Andrew Alston, Group Head of IP Strategy, Liquid Telecommunications
Paul Clarke, Customer Solutions Architect, Fujitsu
Tom Dwyer, Principal Engineer, Nexus
Stefan Fouant, CTO, ShortestPathFirst
Chris Parker, Senior Network Engineer, Nominet
Nick Ryce, Senior Network Architect, Commsworld
Christian Scholz, Senior Consultant Network & Security, Telonic