Reproducer with DHCP server/client on LXD. [Focal]

Bridge
---

        sudo ip link add focalbr type bridge
        sudo ip link set focalbr up


LXD container for DHCP server with classless static routes option
---

        lxc init ubuntu:focal focal-dhcpd
        lxc config device add focal-dhcpd eth0 nic nictype=bridged 
parent=focalbr
        lxc config device add focal-dhcpd eth1 nic nictype=bridged parent=lxdbr0

        lxc start focal-dhcpd
        lxc shell focal-dhcpd

        dhclient eth1

...

        ip addr add 10.11.12.13/24 dev eth0

        apt install -y isc-dhcp-server

        echo 'INTERFACESv4="eth0"' >>/etc/default/isc-dhcp-server

        cat <<EOF >>/etc/dhcp/dhcpd.conf
        option rfc3442-classless-static-routes code 121 = array of integer 8;

        subnet 10.11.12.0 netmask 255.255.255.0 {

          range 10.11.12.100 10.11.12.110;

          option routers 10.11.12.13;

          option rfc3442-classless-static-routes
            0,              10, 11, 12, 200,
            8,  1,          10, 11, 12, 208,
            16, 2, 1,       10, 11, 12, 216,
            24, 3, 2, 1,    10, 11, 12, 224,
            32, 4, 3, 2, 1, 10, 11, 12, 232;
        }
        EOF

        systemctl restart isc-dhcp-server.service


LXD VM for DHCP client
---

        lxc init ubuntu:focal focal-dhclient --vm
        lxc config device add focal-dhclient eth0 nic nictype=bridged 
parent=focalbr
        # no regular lxdbr0 bridge / internet access.

        lxc start focal-dhclient
        lxc shell focal-dhclient

        # ip link
        1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
mode DEFAULT group default qlen 1000
            link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        2: enp5s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP 
mode DEFAULT group default qlen 1000
            link/ether 00:16:3e:36:6b:c8 brd ff:ff:ff:ff:ff:ff

        # ip addr
        1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
group default qlen 1000
            link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
            inet 127.0.0.1/8 scope host lo
               valid_lft forever preferred_lft forever
            inet6 ::1/128 scope host
               valid_lft forever preferred_lft forever
        2: enp5s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP 
group default qlen 1000
            link/ether 00:16:3e:36:6b:c8 brd ff:ff:ff:ff:ff:ff
            inet 10.11.12.101/24 brd 10.11.12.255 scope global dynamic enp5s0
               valid_lft 582sec preferred_lft 582sec
            inet6 fe80::216:3eff:fe36:6bc8/64 scope link
               valid_lft forever preferred_lft forever

        # ip route
        default via 10.11.12.200 dev enp5s0 proto dhcp src 10.11.12.101 metric 
100
        1.0.0.0/8 via 10.11.12.208 dev enp5s0 proto dhcp src 10.11.12.101 
metric 100
        2.1.0.0/16 via 10.11.12.216 dev enp5s0 proto dhcp src 10.11.12.101 
metric 100
        3.2.1.0/24 via 10.11.12.224 dev enp5s0 proto dhcp src 10.11.12.101 
metric 100
        4.3.2.1 via 10.11.12.232 dev enp5s0 proto dhcp src 10.11.12.101 metric 
100
        10.11.12.0/24 dev enp5s0 proto kernel scope link src 10.11.12.101

Ok, all good from booted system's perspective.

Let's check at initramfs time, manually.

The classless routes aren't added if you run dhclient at the current
version.

        cat <<EOF >/etc/default/grub.d/99-grub-initrd.cfg
        GRUB_FORCE_PARTUUID=
        GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT console=ttyS0 
break=bottom"
        EOF

        update-grub && poweroff

        lxc start --console focal-dhclient

        (initramfs) ip addr
        1: lo: <LOOPBACK> mtu 65536 qdisc noop qlen 1000
            link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        2: enp5s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 1000
            link/ether 00:16:3e:36:6b:c8 brd ff:ff:ff:ff:ff:ff

        (initramfs) ip route
        (initramfs)

        (initramfs) dhclient enp5s0
        sed: /etc/resolv.conf: No such file or directory

        (initramfs) ip addr
        1: lo: <LOOPBACK> mtu 65536 qdisc noop qlen 1000
            link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        2: enp5s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000
            link/ether 00:16:3e:36:6b:c8 brd ff:ff:ff:ff:ff:ff
            inet 10.11.12.102/24 brd 10.11.12.255 scope global enp5s0
               valid_lft forever preferred_lft forever
            inet6 fe80::216:3eff:fe36:6bc8/64 scope link
               valid_lft forever preferred_lft forever

        (initramfs) ip route
        10.11.12.0/24 dev enp5s0 scope link  src 10.11.12.102

        (initramfs) dhclient -r enp5s0
        (initramfs) exit


Test package (download it from dhcp server container)
---

@ focal-dhcpd:
        add-apt-repository -y ppa:mfo/lp1926139
        apt download isc-dhcp-client
        python3 -m http.server

@ focal-dhclient:

        wget 10.11.12.13:8000/isc-dhcp-client_4.4.1-2.1ubuntu5.20.04.5_amd64.deb
        dpkg -i isc-dhcp-client_4.4.1-2.1ubuntu5.20.04.5_amd64.deb

Update the initramfs:

        # lsinitramfs /boot/initrd.img-$(uname -r) | grep dhclient-exit-hooks.d
        #

        update-initramfs -u

        # lsinitramfs /boot/initrd.img-$(uname -r) | grep dhclient-exit-hooks.d
        etc/dhcp/dhclient-exit-hooks.d
        etc/dhcp/dhclient-exit-hooks.d/rfc3442-classless-routes

        # poweroff

Try again:

        lxc start --console focal-dhclient

The classless routes ARE added if you run dhclient with the test
package.

        (initramfs) ip addr
        1: lo: <LOOPBACK> mtu 65536 qdisc noop qlen 1000
            link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        2: enp5s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 1000
            link/ether 00:16:3e:36:6b:c8 brd ff:ff:ff:ff:ff:ff
            
        (initramfs) ip route
        (initramfs)

        (initramfs) dhclient enp5s0
        sed: /etc/resolv.conf: No such file or directory

        (initramfs) ip addr
        1: lo: <LOOPBACK> mtu 65536 qdisc noop qlen 1000
            link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        2: enp5s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000
            link/ether 00:16:3e:36:6b:c8 brd ff:ff:ff:ff:ff:ff
            inet 10.11.12.103/24 brd 10.11.12.255 scope global enp5s0
               valid_lft forever preferred_lft forever
            inet6 fe80::216:3eff:fe36:6bc8/64 scope link
               valid_lft forever preferred_lft forever

        (initramfs) ip route
        default via 10.11.12.200 dev enp5s0
        1.0.0.0/8 via 10.11.12.208 dev enp5s0
        2.1.0.0/16 via 10.11.12.216 dev enp5s0
        3.2.1.0/24 via 10.11.12.224 dev enp5s0
        4.3.2.1 via 10.11.12.232 dev enp5s0
        10.11.12.0/24 dev enp5s0 scope link  src 10.11.12.103

        (initramfs) dhclient -r enp5s0
        (initramfs) exit

Now let's check that `ip=dhcp` is working (break=init stops after it
runs):

        cat <<EOF >/etc/default/grub.d/99-grub-initrd.cfg
        GRUB_FORCE_PARTUUID=
        GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT console=ttyS0 
ip=dhcp break=init"
        EOF

        update-grub && poweroff

        lxc start --console focal-dhclient

And yes, it is.

        (initramfs) ip addr
        1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
            link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
            inet 127.0.0.1/8 scope host lo
               valid_lft forever preferred_lft forever
            inet6 ::1/128 scope host
               valid_lft forever preferred_lft forever
        2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000
            link/ether 00:16:3e:36:6b:c8 brd ff:ff:ff:ff:ff:ff
            inet 10.11.12.104/24 brd 10.11.12.255 scope global eth0
               valid_lft forever preferred_lft forever
            inet6 fe80::216:3eff:fe36:6bc8/64 scope link
               valid_lft forever preferred_lft forever

        (initramfs) ip route
        default via 10.11.12.13 dev eth0
        1.0.0.0/8 via 10.11.12.208 dev eth0
        2.1.0.0/16 via 10.11.12.216 dev eth0
        3.2.1.0/24 via 10.11.12.224 dev eth0
        4.3.2.1 via 10.11.12.232 dev eth0
        10.11.12.0/24 dev eth0 scope link  src 10.11.12.104
        (initramfs) 

Clean up:

        lxc stop ...
        lxc delete ...
        sudo ip link del focalbr

-- 
You received this bug notification because you are a member of Ubuntu
Touch seeded packages, which is subscribed to isc-dhcp in Ubuntu.
https://bugs.launchpad.net/bugs/1937110

Title:
  dhcp option 121 & 249

Status in subiquity:
  New
Status in isc-dhcp package in Ubuntu:
  Fix Released
Status in isc-dhcp source package in Focal:
  In Progress
Status in isc-dhcp source package in Jammy:
  In Progress

Bug description:
  [Impact]

   * DHCP classless static routes aren't applied
     by dhclient at the initramfs (e.g., ip=dhcp).

   * This happens as rfc3442-classless-routes is
     not copied to /etc/dhcp/dhclient-exit-hooks.d/
     in the initramfs.

   * On Jammy, if such DHCP option(s) are present
     in the DHCP server response, the DHCP client
     ignores the 'routers' option from the server,
     thus leaving no routes configured.

   * On Focal, the older code still adds 'routers',
     which is slightly better, but still does not
     add the classless static routes.

  [Test Plan]

   * Use LXD container/VMs for DHCP server/client,
     configure the DHCP server with option 121,
     and some sample classless static routes.
     (see comments #12/jammy and #13/focal).

  [Regression Potential]

   * Acquisition of DHCP leases/routes at initramfs
     with ip=dhcp.

   * The code/script is not new, and is exercised
     normally during on rootfs (ie, post-initramfs)
     when dhclient is run.

   * It's also been in the initramfs in Kinetic
     already, since on Aug 2022; giving it tests.

  [Original Description]
  Hello,

  I'm running into issues with subiquity on a cloud provider.  The cloud
  provider is using an on-link L3 gateway.

  His DHCP response looks like this:

  OPTION:  53 (  1) DHCP message type         5 (DHCPACK)
  OPTION:  54 (  4) Server identifier         172.31.1.1
  OPTION:  51 (  4) IP address leasetime      86400 (24h)
  OPTION:   1 (  4) Subnet mask               255.255.255.255
  OPTION:   3 (  4) Routers                   172.31.1.1
  OPTION:   6 ( 12) DNS server                ....
  OPTION: 121 ( 14) Classless Static Route    20ac1f0101000000  .......
           0000ac1f0101     ......
  OPTION: 249 ( 14) MSFT - Classless route    20ac1f0101000000  .......
           0000ac1f0101     ......

  Im booting the subiquity process with an patched ipxe
  (https://github.com/ipxe/ipxe/pull/104) like this:

  #!ipxe
  kernel .../vmlinuz initrd=initrd root=/dev/ram0 ramdisk_size=1500000 ip=dhcp 
url=https://cdimage.ubuntu.com/ubuntu-server/focal/daily-live/current/focal-live-server-amd64.iso
 autoinstall ds=nocloud-net;s=.../...-ad-78/ cloud-config-url=/dev/null
  initrd .../initrd
  boot

  initrd/vmlinuz is extracted right out of focal-live-server-amd64.iso

  Sadly subiquity is stuck with a broken network (because of missing
  dhcp option 121/249 support). It happens when its running the /init
  from the kernel right after kernel is booted, i guess even before the
  subiquity is started(?).

  After further debugging, it looks like the provided kernel 5.4.80 #90
  Ubuntu, is using busybox 1.30.1-4ubuntu~6.3 which includes isc-
  dhclient-4.4.1 which is lacking the given options.

  Would be awesome if this could be fixed.. maybe just a simple busybox
  compile option?

To manage notifications about this bug go to:
https://bugs.launchpad.net/subiquity/+bug/1937110/+subscriptions


-- 
Mailing list: https://launchpad.net/~touch-packages
Post to     : touch-packages@lists.launchpad.net
Unsubscribe : https://launchpad.net/~touch-packages
More help   : https://help.launchpad.net/ListHelp

Reply via email to