github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/network_linux.go (about) 1 // +build linux 2 3 package libcontainer 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "net" 9 "path/filepath" 10 "strconv" 11 "strings" 12 13 "github.com/opencontainers/runc/libcontainer/configs" 14 "github.com/opencontainers/runc/libcontainer/utils" 15 "github.com/vishvananda/netlink" 16 ) 17 18 var strategies = map[string]networkStrategy{ 19 "veth": &veth{}, 20 "loopback": &loopback{}, 21 } 22 23 // networkStrategy represents a specific network configuration for 24 // a container's networking stack 25 type networkStrategy interface { 26 create(*network, int) error 27 initialize(*network) error 28 detach(*configs.Network) error 29 attach(*configs.Network) error 30 } 31 32 // getStrategy returns the specific network strategy for the 33 // provided type. 34 func getStrategy(tpe string) (networkStrategy, error) { 35 s, exists := strategies[tpe] 36 if !exists { 37 return nil, fmt.Errorf("unknown strategy type %q", tpe) 38 } 39 return s, nil 40 } 41 42 // Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo. 43 func getNetworkInterfaceStats(interfaceName string) (*NetworkInterface, error) { 44 out := &NetworkInterface{Name: interfaceName} 45 // This can happen if the network runtime information is missing - possible if the 46 // container was created by an old version of libcontainer. 47 if interfaceName == "" { 48 return out, nil 49 } 50 type netStatsPair struct { 51 // Where to write the output. 52 Out *uint64 53 // The network stats file to read. 54 File string 55 } 56 // Ingress for host veth is from the container. Hence tx_bytes stat on the host veth is actually number of bytes received by the container. 57 netStats := []netStatsPair{ 58 {Out: &out.RxBytes, File: "tx_bytes"}, 59 {Out: &out.RxPackets, File: "tx_packets"}, 60 {Out: &out.RxErrors, File: "tx_errors"}, 61 {Out: &out.RxDropped, File: "tx_dropped"}, 62 63 {Out: &out.TxBytes, File: "rx_bytes"}, 64 {Out: &out.TxPackets, File: "rx_packets"}, 65 {Out: &out.TxErrors, File: "rx_errors"}, 66 {Out: &out.TxDropped, File: "rx_dropped"}, 67 } 68 for _, netStat := range netStats { 69 data, err := readSysfsNetworkStats(interfaceName, netStat.File) 70 if err != nil { 71 return nil, err 72 } 73 *(netStat.Out) = data 74 } 75 return out, nil 76 } 77 78 // Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics 79 func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) { 80 data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile)) 81 if err != nil { 82 return 0, err 83 } 84 return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) 85 } 86 87 // loopback is a network strategy that provides a basic loopback device 88 type loopback struct { 89 } 90 91 func (l *loopback) create(n *network, nspid int) error { 92 return nil 93 } 94 95 func (l *loopback) initialize(config *network) error { 96 return netlink.LinkSetUp(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: "lo"}}) 97 } 98 99 func (l *loopback) attach(n *configs.Network) (err error) { 100 return nil 101 } 102 103 func (l *loopback) detach(n *configs.Network) (err error) { 104 return nil 105 } 106 107 // veth is a network strategy that uses a bridge and creates 108 // a veth pair, one that is attached to the bridge on the host and the other 109 // is placed inside the container's namespace 110 type veth struct { 111 } 112 113 func (v *veth) detach(n *configs.Network) (err error) { 114 return netlink.LinkSetMaster(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: n.HostInterfaceName}}, nil) 115 } 116 117 // attach a container network interface to an external network 118 func (v *veth) attach(n *configs.Network) (err error) { 119 brl, err := netlink.LinkByName(n.Bridge) 120 if err != nil { 121 return err 122 } 123 br, ok := brl.(*netlink.Bridge) 124 if !ok { 125 return fmt.Errorf("Wrong device type %T", brl) 126 } 127 host, err := netlink.LinkByName(n.HostInterfaceName) 128 if err != nil { 129 return err 130 } 131 132 if err := netlink.LinkSetMaster(host, br); err != nil { 133 return err 134 } 135 if err := netlink.LinkSetMTU(host, n.Mtu); err != nil { 136 return err 137 } 138 if n.HairpinMode { 139 if err := netlink.LinkSetHairpin(host, true); err != nil { 140 return err 141 } 142 } 143 if err := netlink.LinkSetUp(host); err != nil { 144 return err 145 } 146 147 return nil 148 } 149 150 func (v *veth) create(n *network, nspid int) (err error) { 151 tmpName, err := v.generateTempPeerName() 152 if err != nil { 153 return err 154 } 155 n.TempVethPeerName = tmpName 156 if n.Bridge == "" { 157 return fmt.Errorf("bridge is not specified") 158 } 159 veth := &netlink.Veth{ 160 LinkAttrs: netlink.LinkAttrs{ 161 Name: n.HostInterfaceName, 162 TxQLen: n.TxQueueLen, 163 }, 164 PeerName: n.TempVethPeerName, 165 } 166 if err := netlink.LinkAdd(veth); err != nil { 167 return err 168 } 169 defer func() { 170 if err != nil { 171 netlink.LinkDel(veth) 172 } 173 }() 174 if err := v.attach(&n.Network); err != nil { 175 return err 176 } 177 child, err := netlink.LinkByName(n.TempVethPeerName) 178 if err != nil { 179 return err 180 } 181 return netlink.LinkSetNsPid(child, nspid) 182 } 183 184 func (v *veth) generateTempPeerName() (string, error) { 185 return utils.GenerateRandomName("veth", 7) 186 } 187 188 func (v *veth) initialize(config *network) error { 189 peer := config.TempVethPeerName 190 if peer == "" { 191 return fmt.Errorf("peer is not specified") 192 } 193 child, err := netlink.LinkByName(peer) 194 if err != nil { 195 return err 196 } 197 if err := netlink.LinkSetDown(child); err != nil { 198 return err 199 } 200 if err := netlink.LinkSetName(child, config.Name); err != nil { 201 return err 202 } 203 // get the interface again after we changed the name as the index also changes. 204 if child, err = netlink.LinkByName(config.Name); err != nil { 205 return err 206 } 207 if config.MacAddress != "" { 208 mac, err := net.ParseMAC(config.MacAddress) 209 if err != nil { 210 return err 211 } 212 if err := netlink.LinkSetHardwareAddr(child, mac); err != nil { 213 return err 214 } 215 } 216 ip, err := netlink.ParseAddr(config.Address) 217 if err != nil { 218 return err 219 } 220 if err := netlink.AddrAdd(child, ip); err != nil { 221 return err 222 } 223 if config.IPv6Address != "" { 224 ip6, err := netlink.ParseAddr(config.IPv6Address) 225 if err != nil { 226 return err 227 } 228 if err := netlink.AddrAdd(child, ip6); err != nil { 229 return err 230 } 231 } 232 if err := netlink.LinkSetMTU(child, config.Mtu); err != nil { 233 return err 234 } 235 if err := netlink.LinkSetUp(child); err != nil { 236 return err 237 } 238 if config.Gateway != "" { 239 gw := net.ParseIP(config.Gateway) 240 if err := netlink.RouteAdd(&netlink.Route{ 241 Scope: netlink.SCOPE_UNIVERSE, 242 LinkIndex: child.Attrs().Index, 243 Gw: gw, 244 }); err != nil { 245 return err 246 } 247 } 248 if config.IPv6Gateway != "" { 249 gw := net.ParseIP(config.IPv6Gateway) 250 if err := netlink.RouteAdd(&netlink.Route{ 251 Scope: netlink.SCOPE_UNIVERSE, 252 LinkIndex: child.Attrs().Index, 253 Gw: gw, 254 }); err != nil { 255 return err 256 } 257 } 258 return nil 259 }