github.com/coreos/mantle@v0.13.0/platform/local/dnsmasq.go (about) 1 // Copyright 2015 CoreOS, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package local 16 17 import ( 18 "fmt" 19 "net" 20 "text/template" 21 22 "github.com/coreos/pkg/capnslog" 23 "github.com/vishvananda/netlink" 24 25 "github.com/coreos/mantle/system/exec" 26 "github.com/coreos/mantle/util" 27 ) 28 29 type Interface struct { 30 HardwareAddr net.HardwareAddr 31 DHCPv4 []net.IPNet 32 DHCPv6 []net.IPNet 33 //SLAAC net.IPAddr 34 } 35 36 type Segment struct { 37 BridgeName string 38 BridgeIf *Interface 39 Interfaces []*Interface 40 nextIf int 41 } 42 43 type Dnsmasq struct { 44 Segments []*Segment 45 dnsmasq *exec.ExecCmd 46 } 47 48 const ( 49 numInterfaces = 500 // affects dnsmasq startup time 50 numSegments = 1 51 52 debugConfig = ` 53 log-queries 54 log-dhcp 55 ` 56 57 quietConfig = ` 58 quiet-dhcp 59 quiet-dhcp6 60 quiet-ra 61 ` 62 63 commonConfig = ` 64 keep-in-foreground 65 leasefile-ro 66 log-facility=- 67 pid-file= 68 69 no-resolv 70 no-hosts 71 enable-ra 72 73 # point NTP at this host (0.0.0.0 and :: are special) 74 dhcp-option=option:ntp-server,0.0.0.0 75 dhcp-option=option6:ntp-server,[::] 76 77 {{range .Segments}} 78 domain={{.BridgeName}}.local 79 80 {{range .BridgeIf.DHCPv4}} 81 dhcp-range={{.IP}},static 82 {{end}} 83 84 {{range .BridgeIf.DHCPv6}} 85 dhcp-range={{.IP}},ra-names,slaac 86 {{end}} 87 88 {{range .Interfaces}} 89 dhcp-host={{.HardwareAddr}}{{template "ips" .DHCPv4}}{{template "ips" .DHCPv6}} 90 {{end}} 91 {{end}} 92 93 {{define "ips"}}{{range .}}{{printf ",%s" .IP}}{{end}}{{end}} 94 ` 95 ) 96 97 var plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "platform/local") 98 99 func newInterface(s byte, i uint16) *Interface { 100 return &Interface{ 101 HardwareAddr: net.HardwareAddr{0x02, s, 0, 0, byte(i / 256), byte(i % 256)}, 102 DHCPv4: []net.IPNet{{ 103 IP: net.IP{10, s, byte(i / 256), byte(i % 256)}, 104 Mask: net.CIDRMask(16, 32)}}, 105 DHCPv6: []net.IPNet{{ 106 IP: net.IP{0xfd, s, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, byte(i / 256), byte(i % 256)}, 107 Mask: net.CIDRMask(64, 128)}}, 108 } 109 } 110 111 func newSegment(s byte) (*Segment, error) { 112 seg := &Segment{ 113 BridgeName: fmt.Sprintf("br%d", s), 114 BridgeIf: newInterface(s, 1), 115 } 116 117 for i := uint16(2); i < 2+numInterfaces; i++ { 118 seg.Interfaces = append(seg.Interfaces, newInterface(s, i)) 119 } 120 121 br := netlink.Bridge{ 122 LinkAttrs: netlink.LinkAttrs{ 123 Name: seg.BridgeName, 124 HardwareAddr: seg.BridgeIf.HardwareAddr, 125 }, 126 } 127 128 if err := netlink.LinkAdd(&br); err != nil { 129 return nil, fmt.Errorf("LinkAdd() failed: %v", err) 130 } 131 132 for _, addr := range seg.BridgeIf.DHCPv4 { 133 nladdr := netlink.Addr{IPNet: &addr} 134 if err := netlink.AddrAdd(&br, &nladdr); err != nil { 135 return nil, fmt.Errorf("DHCPv4 AddrAdd() failed: %v", err) 136 } 137 } 138 139 for _, addr := range seg.BridgeIf.DHCPv6 { 140 nladdr := netlink.Addr{IPNet: &addr} 141 if err := netlink.AddrAdd(&br, &nladdr); err != nil { 142 return nil, fmt.Errorf("DHCPv6 AddrAdd() failed: %v", err) 143 } 144 } 145 146 if err := netlink.LinkSetUp(&br); err != nil { 147 return nil, fmt.Errorf("LinkSetUp() failed: %v", err) 148 } 149 150 return seg, nil 151 } 152 153 func NewDnsmasq() (*Dnsmasq, error) { 154 dm := &Dnsmasq{} 155 for s := byte(0); s < numSegments; s++ { 156 seg, err := newSegment(s) 157 if err != nil { 158 return nil, fmt.Errorf("Network setup failed: %v", err) 159 } 160 dm.Segments = append(dm.Segments, seg) 161 } 162 163 // setup lo 164 lo, err := netlink.LinkByName("lo") 165 if err != nil { 166 return nil, fmt.Errorf("Network loopback setup failed: %v", err) 167 } 168 err = netlink.LinkSetUp(lo) 169 if err != nil { 170 return nil, fmt.Errorf("Network loopback setup failed: %v", err) 171 } 172 173 dm.dnsmasq = exec.Command("dnsmasq", "--conf-file=-") 174 cfg, err := dm.dnsmasq.StdinPipe() 175 if err != nil { 176 return nil, err 177 } 178 out, err := dm.dnsmasq.StdoutPipe() 179 if err != nil { 180 return nil, err 181 } 182 dm.dnsmasq.Stderr = dm.dnsmasq.Stdout 183 go util.LogFrom(capnslog.INFO, out) 184 185 if err = dm.dnsmasq.Start(); err != nil { 186 cfg.Close() 187 return nil, err 188 } 189 190 var configTemplate *template.Template 191 192 if plog.LevelAt(capnslog.DEBUG) { 193 configTemplate = template.Must( 194 template.New("dnsmasq").Parse(debugConfig + commonConfig)) 195 } else { 196 configTemplate = template.Must( 197 template.New("dnsmasq").Parse(quietConfig + commonConfig)) 198 } 199 200 if err = configTemplate.Execute(cfg, dm); err != nil { 201 cfg.Close() 202 dm.Destroy() 203 return nil, err 204 } 205 cfg.Close() 206 207 return dm, nil 208 } 209 210 func (dm *Dnsmasq) GetInterface(bridge string) (in *Interface) { 211 for _, seg := range dm.Segments { 212 if bridge == seg.BridgeName { 213 if seg.nextIf >= len(seg.Interfaces) { 214 panic("Not enough interfaces!") 215 } 216 in = seg.Interfaces[seg.nextIf] 217 seg.nextIf++ 218 return 219 } 220 } 221 panic("Not a valid bridge!") 222 } 223 224 func (dm *Dnsmasq) Destroy() { 225 if err := dm.dnsmasq.Kill(); err != nil { 226 plog.Errorf("Error killing dnsmasq: %v", err) 227 } 228 }