github.com/cilium/cilium@v1.16.2/pkg/mtu/detect_linux.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 //go:build linux 5 6 package mtu 7 8 import ( 9 "fmt" 10 "net" 11 12 "github.com/sirupsen/logrus" 13 "github.com/vishvananda/netlink" 14 15 "github.com/cilium/cilium/pkg/logging/logfields" 16 ) 17 18 const ( 19 // externalProbeIPv4 is an IPv4 address specifically designed for tests. We 20 // only want to retrieve default route for external IP addresses, thus it 21 // doesn't need to be a real address. 22 externalProbeIPv4 = "203.0.113.1" 23 24 // externalProbeIPv6 is an IPv4 address specifically designed for tests. We 25 // only want to retrieve default route for external IP addresses, thus it 26 // doesn't need to be a real address. 27 externalProbeIPv6 = "2001:db8::1" 28 ) 29 30 func getRoute(externalProbe string) ([]netlink.Route, error) { 31 ip := net.ParseIP(externalProbe) 32 if ip == nil { 33 return nil, fmt.Errorf("unable to parse IP %s", externalProbe) 34 } 35 36 routes, err := netlink.RouteGet(ip) 37 if err != nil { 38 return nil, fmt.Errorf("unable to lookup route to %s: %w", externalProbe, err) 39 } 40 41 if len(routes) == 0 { 42 return nil, fmt.Errorf("no route to %s", externalProbe) 43 } 44 45 return routes, nil 46 } 47 48 func autoDetect() (int, error) { 49 var routes []netlink.Route 50 var err error 51 52 routes, err = getRoute(externalProbeIPv4) 53 if err != nil { 54 prevErr := err 55 routes, err = getRoute(externalProbeIPv6) 56 if err != nil { 57 return 0, fmt.Errorf("%w: %w", err, prevErr) 58 } 59 } 60 61 if routes[0].Gw == nil { 62 return 0, fmt.Errorf("unable to find default gateway from the routes: %s", routes) 63 } 64 65 link, err := netlink.LinkByIndex(routes[0].LinkIndex) 66 if err != nil { 67 return 0, fmt.Errorf("unable to find interface of default route: %w", err) 68 } 69 70 if mtu := link.Attrs().MTU; mtu != 0 { 71 log.Infof("Detected MTU %d", mtu) 72 return mtu, nil 73 } 74 75 return EthernetMTU, nil 76 } 77 78 // getMTUFromIf finds the interface that holds the ip and returns its mtu 79 func getMTUFromIf(ip net.IP) (int, error) { 80 ifaces, err := netlink.LinkList() 81 if err != nil { 82 return 0, fmt.Errorf("unable to list interfaces: %w", err) 83 } 84 85 for _, iface := range ifaces { 86 addrs, err := netlink.AddrList(iface, netlink.FAMILY_ALL) 87 if err != nil { 88 log.WithFields(logrus.Fields{ 89 logfields.Device: iface.Attrs().Name, 90 }).Warning("Unable to list all addresses") 91 continue 92 } 93 94 for _, addr := range addrs { 95 if addr.IPNet.IP.Equal(ip) { 96 myMTU := iface.Attrs().MTU 97 log.WithFields(logrus.Fields{ 98 logfields.Device: iface.Attrs().Name, 99 logfields.IPAddr: ip, 100 logfields.MTU: myMTU, 101 }).Info("Inheriting MTU from external network interface") 102 return myMTU, nil 103 } 104 } 105 } 106 return 0, fmt.Errorf("No interface contains the provided ip: %v", ip) 107 }