1
2
3
4 package network
5
6 import (
7 "bytes"
8 "context"
9 "fmt"
10 "os"
11 "path/filepath"
12 "strings"
13 "time"
14
15 "github.com/Microsoft/hcsshim/internal/guest/storage"
16 "github.com/Microsoft/hcsshim/internal/guest/storage/pci"
17 "github.com/Microsoft/hcsshim/internal/guest/storage/vmbus"
18 "github.com/Microsoft/hcsshim/internal/log"
19 "github.com/Microsoft/hcsshim/internal/oc"
20 "github.com/pkg/errors"
21 "go.opencensus.io/trace"
22 )
23
24
25 var (
26 pciFindDeviceFullPath = pci.FindDeviceFullPath
27 storageWaitForFileMatchingPattern = storage.WaitForFileMatchingPattern
28 vmbusWaitForDevicePath = vmbus.WaitForDevicePath
29 ioReadDir = os.ReadDir
30 )
31
32
33 const maxDNSSearches = 6
34
35
36 func GenerateEtcHostsContent(ctx context.Context, hostname string) string {
37 _, span := oc.StartSpan(ctx, "network::GenerateEtcHostsContent")
38 defer span.End()
39 span.AddAttributes(trace.StringAttribute("hostname", hostname))
40
41 nameParts := strings.Split(hostname, ".")
42 buf := bytes.Buffer{}
43 buf.WriteString("127.0.0.1 localhost\n")
44 if len(nameParts) > 1 {
45 buf.WriteString(fmt.Sprintf("127.0.0.1 %s %s\n", hostname, nameParts[0]))
46 } else {
47 buf.WriteString(fmt.Sprintf("127.0.0.1 %s\n", hostname))
48 }
49 buf.WriteString("\n")
50 buf.WriteString("# The following lines are desirable for IPv6 capable hosts\n")
51 buf.WriteString("::1 ip6-localhost ip6-loopback\n")
52 buf.WriteString("fe00::0 ip6-localnet\n")
53 buf.WriteString("ff00::0 ip6-mcastprefix\n")
54 buf.WriteString("ff02::1 ip6-allnodes\n")
55 buf.WriteString("ff02::2 ip6-allrouters\n")
56 return buf.String()
57 }
58
59
60
61 func GenerateResolvConfContent(ctx context.Context, searches, servers, options []string) (_ string, err error) {
62 _, span := oc.StartSpan(ctx, "network::GenerateResolvConfContent")
63 defer span.End()
64 defer func() { oc.SetSpanStatus(span, err) }()
65
66 span.AddAttributes(
67 trace.StringAttribute("searches", strings.Join(searches, ", ")),
68 trace.StringAttribute("servers", strings.Join(servers, ", ")),
69 trace.StringAttribute("options", strings.Join(options, ", ")))
70
71 if len(searches) > maxDNSSearches {
72 return "", errors.Errorf("searches has more than %d domains", maxDNSSearches)
73 }
74
75 content := ""
76 if len(searches) > 0 {
77 content += fmt.Sprintf("search %s\n", strings.Join(searches, " "))
78 }
79 if len(servers) > 0 {
80 content += fmt.Sprintf("nameserver %s\n", strings.Join(servers, "\nnameserver "))
81 }
82 if len(options) > 0 {
83 content += fmt.Sprintf("options %s\n", strings.Join(options, " "))
84 }
85 return content, nil
86 }
87
88
89 func MergeValues(first, second []string) []string {
90 if len(first) == 0 {
91 return second
92 }
93 if len(second) == 0 {
94 return first
95 }
96 values := make([]string, len(first), len(first)+len(second))
97 copy(values, first)
98 for _, v := range second {
99 found := false
100 for i := 0; i < len(values); i++ {
101 if v == values[i] {
102 found = true
103 break
104 }
105 }
106 if !found {
107 values = append(values, v)
108 }
109 }
110 return values
111 }
112
113
114
115
116
117 func InstanceIDToName(ctx context.Context, id string, vpciAssigned bool) (_ string, err error) {
118 ctx, span := oc.StartSpan(ctx, "network::InstanceIDToName")
119 defer span.End()
120 defer func() { oc.SetSpanStatus(span, err) }()
121
122 vmBusID := strings.ToLower(id)
123 span.AddAttributes(trace.StringAttribute("adapterInstanceID", vmBusID))
124
125 var netDevicePath string
126 if vpciAssigned {
127 var pciDevicePath string
128 pciDevicePath, err = pciFindDeviceFullPath(ctx, vmBusID)
129 if err != nil {
130 return "", err
131 }
132 pciNetDirPattern := filepath.Join(pciDevicePath, "net")
133 netDevicePath, err = storageWaitForFileMatchingPattern(ctx, pciNetDirPattern)
134 } else {
135 vmBusNetSubPath := filepath.Join(vmBusID, "net")
136 netDevicePath, err = vmbusWaitForDevicePath(ctx, vmBusNetSubPath)
137 }
138 if err != nil {
139 return "", errors.Wrapf(err, "failed to find adapter %v sysfs path", vmBusID)
140 }
141
142 var deviceDirs []os.DirEntry
143 for {
144 deviceDirs, err = ioReadDir(netDevicePath)
145 if err != nil {
146 if os.IsNotExist(err) {
147 select {
148 case <-ctx.Done():
149 return "", errors.Wrap(ctx.Err(), "timed out waiting for net adapter")
150 default:
151 time.Sleep(10 * time.Millisecond)
152 continue
153 }
154 } else {
155 return "", errors.Wrapf(err, "failed to read vmbus network device from /sys filesystem for adapter %s", vmBusID)
156 }
157 }
158 break
159 }
160 if len(deviceDirs) == 0 {
161 return "", errors.Errorf("no interface name found for adapter %s", vmBusID)
162 }
163 if len(deviceDirs) > 1 {
164 return "", errors.Errorf("multiple interface names found for adapter %s", vmBusID)
165 }
166 ifname := deviceDirs[0].Name()
167 log.G(ctx).WithField("ifname", ifname).Debug("resolved ifname")
168 return ifname, nil
169 }
170
View as plain text