router7/cmd/netconfigd/netconfigd.go

172 lines
4.2 KiB
Go
Raw Normal View History

2018-06-28 13:39:48 +02:00
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2018-05-27 17:30:42 +02:00
// Binary netconfigd reads state from dhcp4, dhcp6, … and applies it.
package main
import (
"flag"
"net"
"net/http"
2018-05-27 17:30:42 +02:00
"os"
"os/signal"
"sync"
2018-05-27 17:30:42 +02:00
"syscall"
"github.com/gokrazy/gokrazy"
"github.com/google/nftables"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
2018-07-09 08:54:04 +02:00
"github.com/rtr7/router7/internal/multilisten"
"github.com/rtr7/router7/internal/netconfig"
"github.com/rtr7/router7/internal/notify"
2018-07-09 08:54:04 +02:00
"github.com/rtr7/router7/internal/teelogger"
2018-05-27 17:30:42 +02:00
)
var log = teelogger.NewConsole()
2018-05-27 17:30:42 +02:00
var (
linger = flag.Bool("linger", true, "linger around after applying the configuration (until killed)")
)
func init() {
var c nftables.Conn
for _, metric := range []struct {
name string
labels prometheus.Labels
obj *nftables.CounterObj
packets, bytes uint64
}{
{
name: "filter_forward",
labels: prometheus.Labels{"family": "ipv4"},
obj: &nftables.CounterObj{
Table: &nftables.Table{Family: nftables.TableFamilyIPv4, Name: "filter"},
Name: "fwded",
},
},
{
name: "filter_forward",
labels: prometheus.Labels{"family": "ipv6"},
obj: &nftables.CounterObj{
Table: &nftables.Table{Family: nftables.TableFamilyIPv6, Name: "filter"},
Name: "fwded",
},
},
} {
metric := metric // copy
var mu sync.Mutex
updateCounter := func() {
mu.Lock()
defer mu.Unlock()
objs, err := c.GetObjReset(metric.obj)
if err != nil ||
len(objs) != 1 {
return
}
if co, ok := objs[0].(*nftables.CounterObj); ok {
metric.packets += co.Packets
metric.bytes += co.Bytes
}
}
promauto.NewCounterFunc(
prometheus.CounterOpts{
Subsystem: "nftables",
Name: metric.name + "_packets",
Help: "packet count",
ConstLabels: metric.labels,
},
func() float64 {
updateCounter()
return float64(metric.packets)
})
promauto.NewCounterFunc(
prometheus.CounterOpts{
Subsystem: "nftables",
Name: metric.name + "_bytes",
Help: "bytes count",
ConstLabels: metric.labels,
},
func() float64 {
updateCounter()
return float64(metric.bytes)
})
}
}
var httpListeners = multilisten.NewPool()
func updateListeners() error {
hosts, err := gokrazy.PrivateInterfaceAddrs()
if err != nil {
return err
}
if net1, err := multilisten.IPv6Net1("/perm"); err == nil {
hosts = append(hosts, net1)
}
httpListeners.ListenAndServe(hosts, func(host string) multilisten.Listener {
return &http.Server{Addr: net.JoinHostPort(host, "8066")}
})
return nil
}
2018-05-27 17:30:42 +02:00
func logic() error {
if *linger {
http.Handle("/metrics", promhttp.Handler())
2018-06-27 19:45:55 +02:00
if err := updateListeners(); err != nil {
return err
}
}
2018-05-27 17:30:42 +02:00
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGUSR1)
for {
2018-06-03 20:47:11 +02:00
err := netconfig.Apply("/perm/", "/")
// Notify dhcp4d so that it can update its listeners for prometheus
// metrics on the external interface.
if err := notify.Process("/user/dhcp4d", syscall.SIGUSR1); err != nil {
log.Printf("notifying dhcp4d: %v", err)
}
2018-05-28 09:53:54 +02:00
// Notify gokrazy about new addresses (netconfig.Apply might have
// modified state before returning an error) so that listeners can be
// updated.
p, _ := os.FindProcess(1)
if err := p.Signal(syscall.SIGHUP); err != nil {
log.Printf("kill -HUP 1: %v", err)
}
if err != nil {
2018-05-27 17:30:42 +02:00
return err
}
2018-05-28 09:53:54 +02:00
if !*linger {
break
2018-05-27 17:30:42 +02:00
}
2018-05-28 09:53:54 +02:00
<-ch
if err := updateListeners(); err != nil {
log.Printf("updateListeners: %v", err)
}
2018-05-27 17:30:42 +02:00
}
return nil
}
func main() {
flag.Parse()
if err := logic(); err != nil {
log.Fatal(err)
}
}