Could the Quad have a second ethernet and work as a firewall?

Discussion in 'UDOO QUAD' started by Maurice, Feb 7, 2017.

  1. Maurice

    Maurice Active Member

    Joined:
    Oct 13, 2015
    Messages:
    384
    Likes Received:
    87
    When I receive X86 the Quad I have can be re-purposed, and one of the ideas I'm having is to use it as a firewall between the fibre-modem and the rest of my network. It would require to add a second ethernet via USB and firewall software (such as https://opnsense.org/).[*]

    How feasible would this be, and could I expect that overall internet experience is not slowed down by this?

    [*] Oops, no ARM32 :)
     
  2. fetcher

    fetcher Member

    Joined:
    Mar 9, 2014
    Messages:
    137
    Likes Received:
    7
    I've been using a Quad as my home firewall (as well as router, VPN tunnel host, Asterisk PBX for the phones, small file server, home automation box, etc.) for a couple of years now. USB Ethernet is one option to get a second interface, though that comes with a slight performance bottleneck as well as an increase in latency, like what you see on any model of Raspberry Pi with that board's USB-hosted internal Ethernet. The difference isn't huge, but I preferred to avoid that, and save my USB ports for other things like cellphone-tethering (auto-failover during outages).

    Since Udoo's don't bond out the i.MX6's PCI Express controller (alas, that would have been nice), the only other practical solution to connect the Udoo to a small switch capable of 802.1q VLAN tagging, to allow splitting the single onboard NIC into multiple logical interfaces. This is what a lot of commercial home/small-office routers do internally to get their distinct WAN and LAN ports. With proper use of VLAN tagging, unlike mere aliases (e.g. eth0:0, eth0:1) such interfaces (eth0.0, eth0.1 ...), remain fully separate for security and administrative purposes, though of course they all share bandwidth on the common physical uplink port. You can safely run a dhcp client on one, dhcp server on another, static addressing on more, while applying distinct iptables policies to each.

    Note that throughput of the i.MX6's on-chip Ethernet is limited to just over 400Mb/s, due to internal bus bottlenecks. Only an issue if you run it at Gigabit speed, of course. This is a Freescale limitation, not specific to the Udoo.

    After installing the 'vlan' package under Debian or Ubuntu, the 'vconfig' utility becomes available for setting up tagging and virtual interfaces manually, though at least in Debian they can also just be dropped into /etc/network/interfaces as if they were distinct NICs (using eth0.1, eth0.2 etc. syntax) and the boot scripts will handle this for you.

    The older 3.0.35 Udoo kernel needs a patch to the Freescale Ethernet (fec.c) driver for VLAN support, and its requirement of slightly larger MTUs to work properly. I'll attach it below. Newer kernels may no longer require this, but I haven't yet tried those in this application.

    On the switch side, just about any "enterprise" switch (such as a Cisco Catalyst, Juniper, HP Procurve, Brocade, etc.) has the necessary 802.1q support-- this does have to be configured on the switch as well-- and older models can be found cheaply on the used market, but those tend to be noisy (high-speed fans) and also a bit power-hungry, kind of overkill all around, so I prefer to avoid those for home use. A few smaller-scale switches are now available that can do proper VLANs cheaply without fan noise or excess power use. Netgear's GS108T is one, but I think that one requires a proprietary Windows-based tool to do the one-time tagging setup and other configuration, in lieu of a normal command-line or web interface.

    Certain models of cheap, unmanaged switches, such as 100M models based on Realtek RTL8309SB or RTL8309SC chips, can also be modified to add this feature. This is the route I took. You have to add a 24LC02 serial (i2c) EEPROM chip, programmed in advance with the desired config-register settings based on information in the datasheets for those switch chips. A few may come with traces conveniently routed to an unpopulated DIP-8 or SOIC-8 position to allow easily adding this chip, but more often you have to solder about five fine-pitch wires (e.g. 30 gauge wire-wrap width) directly to the surface-mount switch controller IC, possibly cutting one trace as well. This takes a steady hand, and I wouldn't recommend it if you haven't done surface-mount work before, but this method does allow for very cheap, very low-power-use VLAN fanout. Drop me a line if anyone's interested in EEPROM images for those partiuclar Realtek chips. I like to set them up for five VLANs in all, with three ports in one and a single port in each of the four others, plus of course the common trunk port for an attached Udoo or other router machine.

    Newer generations of these Realtek chips, such as the RTL8309N, unfortunately no longer have datasheets or register maps available for public access. One apparently has to a sign an NDA and jump through some hoops to obtain access, which might not be granted to noncommercial hobbyists even then.

    Here's that 3.0.35 VLAN kernel patch, in diff -u format: [edited to fix a couple of wrapped lines]

    Code:
    diff -ru Kernel_Unico-dist/drivers/net/fec.c kernel_unico_imp/drivers/net/fec.c
    --- Kernel_Unico-dist/drivers/net/fec.c 2014-07-14 20:15:53.000000000 -0400
    +++ kernel_unico_imp/drivers/net/fec.c  2014-07-04 00:32:36.000000000 -0400
    @@ -156,9 +156,13 @@
     /* The FEC stores dest/src/type, data, and checksum for receive packets.
      */
    -#define PKT_MAXBUF_SIZE                1518
    -#define PKT_MINBUF_SIZE                64
    -#define PKT_MAXBLR_SIZE                1520
    +/* -jnh- bump maximums up by 4 for 802.1q ... or a little more?
    + #define PKT_MAXBUF_SIZE               1518
    + #define PKT_MAXBLR_SIZE               1520
    +*/
    + #define PKT_MAXBUF_SIZE               1534
    + #define PKT_MAXBLR_SIZE               1536
    + #define PKT_MINBUF_SIZE               64
     /* Pause frame feild and FIFO threshold */
     #define FEC_ENET_FCE           (1 << 5)
    @@ -603,28 +607,35 @@
                            goto rx_processing_done;
                    /* Check for errors. */
    +               status ^= BD_ENET_RX_LAST;  /* -jnh- this and following from https://github.com/boundarydevices/linux-imx6/commit/23e50de473fec3ba33505768b020d9966f5610f6 */
                    if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
    -                          BD_ENET_RX_CR | BD_ENET_RX_OV)) {
    +                          BD_ENET_RX_CR | BD_ENET_RX_OV | BD_ENET_RX_LAST |
    +                          BD_ENET_RX_CL )) {  /* -jnh- last 2 added */
                            ndev->stats.rx_errors++;
    -                       if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
    -                               /* Frame too long or too short. */
    -                               ndev->stats.rx_length_errors++;
    -                       }
    -                       if (status & BD_ENET_RX_NO)     /* Frame alignment */
    -                               ndev->stats.rx_frame_errors++;
    -                       if (status & BD_ENET_RX_CR)     /* CRC Error */
    -                               ndev->stats.rx_crc_errors++;
    -                       if (status & BD_ENET_RX_OV)     /* FIFO overrun */
    +/* -jnh- this section rewritten:  */
    +                       if (status & BD_ENET_RX_OV) {
    +                               /* FIFO overrun */
                                    ndev->stats.rx_fifo_errors++;
    -               }
    -
    -               /* Report late collisions as a frame error.
    -                * On this error, the BD is closed, but we don't know what we
    -                * have in the buffer.  So, just drop this frame on the floor.
    -                */
    -               if (status & BD_ENET_RX_CL) {
    -                       ndev->stats.rx_errors++;
    -                       ndev->stats.rx_frame_errors++;
    +                       } else {
    +                               if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH
    +                                               | BD_ENET_RX_LAST)) {
    +                                       /* Frame too long or too short */
    +                                       ndev->stats.rx_length_errors++;
    +                                       if (status & BD_ENET_RX_LAST)
    +                                               dev_err(&ndev->dev,
    +                                               "rcv is not +last, "
    +                                               "0x%x\n", status);
    +                               }
    +                               if (status & BD_ENET_RX_CR)     /* CRC Error */
    +                                       ndev->stats.rx_crc_errors++;
    +                               /*
    +                                * Report late collisions as a frame error.
    +                                */
    +        
    +                               if (status & (BD_ENET_RX_NO | BD_ENET_RX_CL))
    +                                       ndev->stats.rx_frame_errors++;
    +                       }
    +/* -jnh- end of rewritten section from above Github patch */
                            goto rx_processing_done;
                    }
    @@ -1668,6 +1679,10 @@
                    writel(OPT_FRAME_SIZE | 0x06, fep->hwp + FEC_R_CNTRL);
                    writel(0x0, fep->hwp + FEC_X_CNTRL);
            }
    +       /* -jnh- per https://github.com/boundarydevices/linux-imx6/commit/f8626240dda0f1c0b517835356a2121a71600b97 */
    +#ifdef FEC_FTRL
    +       writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_FTRL);
    +#endif
            fep->full_duplex = duplex;
            /* Set MII speed */
    diff -ru Kernel_Unico-dist/drivers/net/fec.h kernel_unico_imp/drivers/net/fec.h
    --- Kernel_Unico-dist/drivers/net/fec.h 2014-07-14 20:15:53.000000000 -0400
    +++ kernel_unico_imp/drivers/net/fec.h  2014-07-04 00:10:04.000000000 -0400
    @@ -49,6 +49,8 @@
     #define FEC_R_FIFO_RSEM                0x194 /* Receive FIFO section empty threshold */
     #define FEC_R_FIFO_RAEM                0x198 /* Receive FIFO almost empty threshold */
     #define FEC_R_FIFO_RAFL                0x19c /* Receive FIFO almost full threshold */
    +/* -jnh- per https://github.com/boundarydevices/linux-imx6/commit/f8626240dda0f1c0b517835356a2121a71600b97 : */
    +#define FEC_FTRL               0x1b0 /* Frame truncation receive length*/
     #define FEC_MIIGSK_CFGR                0x300 /* MIIGSK Configuration reg */
     #define FEC_MIIGSK_ENR         0x308 /* MIIGSK Enable reg */
    
     
    Last edited: Feb 25, 2017
    sirrab, Laura, jas-mx and 1 other person like this.
  3. jas-mx

    jas-mx Active Member

    Joined:
    Dec 31, 2013
    Messages:
    365
    Likes Received:
    109
    Excellent post ! Few posts these days contain any technical content.
     

Share This Page