m/n/c/network: static networking fixes

This fixes three issues with static networking:

It joins interfaces to a master in down state as otherwise Linux
can return an error.

It takes up the automatically-created loopback interface as otherwise we
have no working loopback interface which causes some weird breakage.

It also patches netlink to use RTM_SETLINK instead of RTM_NEWLINK for
reconfiguring interfaces as otherwise Linux sometimes returns an error.

Change-Id: I512e38c6edc1a6d964feb552b1a3995165d74730
Reviewed-on: https://review.monogon.dev/c/monogon/+/1523
Tested-by: Jenkins CI
Reviewed-by: Serge Bazanski <serge@monogon.tech>
diff --git a/metropolis/node/core/network/static.go b/metropolis/node/core/network/static.go
index 45469df..29e3c48 100644
--- a/metropolis/node/core/network/static.go
+++ b/metropolis/node/core/network/static.go
@@ -68,13 +68,14 @@
 			return fmt.Errorf("interface %q: %w", i.Name, err)
 		}
 		newLink.Attrs().Name = i.Name
-		// Set link administratively up
-		newLink.Attrs().Flags |= unix.IFF_UP
 		if i.Mtu != 0 {
 			newLink.Attrs().MTU = int(i.Mtu)
 		}
 		if nameParentMap[i.Name] != "" {
 			newLink.Attrs().MasterIndex = nameLinkMap[nameParentMap[i.Name]].Attrs().Index
+		} else {
+			// Set link administratively up if no MasterIndex has been set.
+			newLink.Attrs().Flags |= net.FlagUp
 		}
 		if newLink.Attrs().Index == -1 {
 			if err := netlink.LinkAdd(newLink); err != nil {
@@ -192,7 +193,7 @@
 
 	for _, link := range links {
 		if link.Attrs().EncapType == "loopback" {
-			continue
+			netlink.LinkSetUp(link)
 		}
 		d, ok := link.(*netlink.Device)
 		if !ok {
diff --git a/third_party/go/patches/netlink-use-rtm_setlink.patch b/third_party/go/patches/netlink-use-rtm_setlink.patch
new file mode 100644
index 0000000..7d05d0e
--- /dev/null
+++ b/third_party/go/patches/netlink-use-rtm_setlink.patch
@@ -0,0 +1,65 @@
+From f367f115a327ca07a294022bc296b4a2fd4e8f8c Mon Sep 17 00:00:00 2001
+From: Lorenz Brun <lorenz@monogon.tech>
+Date: Thu, 6 Apr 2023 23:06:03 +0200
+Subject: [PATCH] Use RTM_SETLINK where appropriate
+
+---
+ link_linux.go | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/link_linux.go b/link_linux.go
+index cc80fb6..db89880 100644
+--- a/link_linux.go
++++ b/link_linux.go
+@@ -332,7 +332,7 @@ func BridgeSetMcastSnoop(link Link, on bool) error {
+ func (h *Handle) BridgeSetMcastSnoop(link Link, on bool) error {
+ 	bridge := link.(*Bridge)
+ 	bridge.MulticastSnooping = &on
+-	return h.linkModify(bridge, unix.NLM_F_ACK)
++	return h.linkModify(bridge, unix.RTM_SETLINK, unix.NLM_F_ACK)
+ }
+ 
+ func BridgeSetVlanFiltering(link Link, on bool) error {
+@@ -342,7 +342,7 @@ func BridgeSetVlanFiltering(link Link, on bool) error {
+ func (h *Handle) BridgeSetVlanFiltering(link Link, on bool) error {
+ 	bridge := link.(*Bridge)
+ 	bridge.VlanFiltering = &on
+-	return h.linkModify(bridge, unix.NLM_F_ACK)
++	return h.linkModify(bridge, unix.RTM_SETLINK, unix.NLM_F_ACK)
+ }
+ 
+ func SetPromiscOn(link Link) error {
+@@ -1197,7 +1197,7 @@ func LinkAdd(link Link) error {
+ // are taken from the parameters in the link object.
+ // Equivalent to: `ip link add $link`
+ func (h *Handle) LinkAdd(link Link) error {
+-	return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
++	return h.linkModify(link, unix.RTM_NEWLINK, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
+ }
+ 
+ func LinkModify(link Link) error {
+@@ -1205,10 +1205,10 @@ func LinkModify(link Link) error {
+ }
+ 
+ func (h *Handle) LinkModify(link Link) error {
+-	return h.linkModify(link, unix.NLM_F_REQUEST|unix.NLM_F_ACK)
++	return h.linkModify(link, unix.RTM_SETLINK, unix.NLM_F_REQUEST|unix.NLM_F_ACK)
+ }
+ 
+-func (h *Handle) linkModify(link Link, flags int) error {
++func (h *Handle) linkModify(link Link, proto, flags int) error {
+ 	// TODO: support extra data for macvlan
+ 	base := link.Attrs()
+ 
+@@ -1373,7 +1373,7 @@ func (h *Handle) linkModify(link Link, flags int) error {
+ 		return nil
+ 	}
+ 
+-	req := h.newNetlinkRequest(unix.RTM_NEWLINK, flags)
++	req := h.newNetlinkRequest(proto, flags)
+ 
+ 	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
+ 	// TODO: make it shorter
+-- 
+2.39.2
+
diff --git a/third_party/go/repositories.bzl b/third_party/go/repositories.bzl
index b58c990..c27a5ef 100644
--- a/third_party/go/repositories.bzl
+++ b/third_party/go/repositories.bzl
@@ -4935,6 +4935,7 @@
         patches = [
             # Going upstream as https://github.com/vishvananda/netlink/pull/850
             "//third_party/go/patches:netlink-permhwaddr.patch",
+            "//third_party/go/patches:netlink-use-rtm_setlink.patch",
         ],
         replace = "github.com/monogon-dev/netlink",
         sum = "h1:y05BDqZ6q3if6pYBHJcnQRUd92ihzBEJde/S4fpKEAM=",