From baabc82903203501fedc20ed503f07486ba8005e Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Mon, 5 Apr 2021 23:17:26 +0800 Subject: [PATCH] feature: add a standalone dhcp relay service --- .../root/etc/sysconfig/yunion_dhcprelay | 3 + .../systemd/system/yunion-dhcprelay.service | 22 +++++ build/dhcprelay/vars | 2 + cmd/dhcprelay/main.go | 93 +++++++++++++++++++ pkg/hostman/hostinfo/hostdhcp/dhcpserver.go | 19 +++- pkg/hostman/hostinfo/hostinfo.go | 2 +- pkg/hostman/hostinfo/hostinfohelper.go | 2 +- 7 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 build/dhcprelay/root/etc/sysconfig/yunion_dhcprelay create mode 100644 build/dhcprelay/root/usr/lib/systemd/system/yunion-dhcprelay.service create mode 100644 build/dhcprelay/vars create mode 100644 cmd/dhcprelay/main.go diff --git a/build/dhcprelay/root/etc/sysconfig/yunion_dhcprelay b/build/dhcprelay/root/etc/sysconfig/yunion_dhcprelay new file mode 100644 index 0000000000..019a755c0e --- /dev/null +++ b/build/dhcprelay/root/etc/sysconfig/yunion_dhcprelay @@ -0,0 +1,3 @@ +INTERFACE="" +INTERFACE_IP="" +RELAY="" diff --git a/build/dhcprelay/root/usr/lib/systemd/system/yunion-dhcprelay.service b/build/dhcprelay/root/usr/lib/systemd/system/yunion-dhcprelay.service new file mode 100644 index 0000000000..daed8b9e7b --- /dev/null +++ b/build/dhcprelay/root/usr/lib/systemd/system/yunion-dhcprelay.service @@ -0,0 +1,22 @@ +[Unit] +Description=Yunion Cloud DHCP Relay Agent +Documentation=https://docs.yunion.cn +After=network-online.target +Wants=network-online.target +After=network.target + +[Service] +Type=simple +EnvironmentFile=-/etc/sysconfig/yunion_dhcprelay +User=root +Group=root +ExecStart=/opt/yunion/bin/dhcprelay --interface "$INTERFACE" --ip "$IP" --relay "$RELAY" +WorkingDirectory=/opt/yunion/bin +KillMode=process +Restart=always +RestartSec=30 +LimitNOFILE=500000 +LimitNPROC=500000 + +[Install] +WantedBy=multi-user.target diff --git a/build/dhcprelay/vars b/build/dhcprelay/vars new file mode 100644 index 0000000000..c1f8a5dd95 --- /dev/null +++ b/build/dhcprelay/vars @@ -0,0 +1,2 @@ +DESCRIPTION="Yunion Tiny DHCP Relay Server" +SERVICE="yes" diff --git a/cmd/dhcprelay/main.go b/cmd/dhcprelay/main.go new file mode 100644 index 0000000000..f5fc4b8e35 --- /dev/null +++ b/cmd/dhcprelay/main.go @@ -0,0 +1,93 @@ +// Copyright 2019 Yunion +// +// 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. + +package main + +import ( + "fmt" + "os" + "time" + + "yunion.io/x/pkg/errors" + "yunion.io/x/structarg" + + "yunion.io/x/onecloud/pkg/hostman/hostinfo/hostdhcp" + "yunion.io/x/onecloud/pkg/util/atexit" +) + +type Options struct { + Help bool `help:"Show help"` + Interface string `help:"Listening interface, e.g. eth0"` + Ip string `help:"Listening interface IP, e.g. 192.168.22.2"` + Port int `help:"listening port" default:"67"` + Relay string `help:"Relay server address, e.g. 192.168.22.23"` +} + +func relayMain() error { + parse, err := structarg.NewArgumentParser(&Options{}, + "dhcprelay", + "An independent dhcp relay.", + `See "dhcprelay --help" for help.`) + + if err != nil { + return err + } + + err = parse.ParseArgs(os.Args[1:], false) + options := parse.Options().(*Options) + + if options.Help { + fmt.Print(parse.HelpString()) + return errors.Error("Need help!") + } + + if len(options.Interface) == 0 { + return errors.Error("Missing interface") + } + if len(options.Ip) == 0 { + return errors.Error("Missing interface IP") + } + if len(options.Relay) == 0 { + return errors.Error("Missing DHCP relay server") + } + + srv, err := hostdhcp.NewGuestDHCPServer(options.Interface, options.Port, []string{ + options.Relay, "67", + }) + + if err != nil { + return errors.Wrap(err, "NewGuestDHCPServer") + } + + srv.Start(false) + + srv.RelaySetup(options.Ip) + + for { + time.Sleep(time.Hour) + } + + return nil +} + +func main() { + defer atexit.Handle() + + err := relayMain() + + if err != nil { + fmt.Fprintf(os.Stdout, "Error: %s", err) + os.Exit(-1) + } +} diff --git a/pkg/hostman/hostinfo/hostdhcp/dhcpserver.go b/pkg/hostman/hostinfo/hostdhcp/dhcpserver.go index 43c61378f9..0c32c3a181 100644 --- a/pkg/hostman/hostinfo/hostdhcp/dhcpserver.go +++ b/pkg/hostman/hostinfo/hostdhcp/dhcpserver.go @@ -41,7 +41,7 @@ type SGuestDHCPServer struct { iface string } -func NewGuestDHCPServer(iface string, relay []string) (*SGuestDHCPServer, error) { +func NewGuestDHCPServer(iface string, port int, relay []string) (*SGuestDHCPServer, error) { var ( err error guestdhcp = new(SGuestDHCPServer) @@ -51,7 +51,7 @@ func NewGuestDHCPServer(iface string, relay []string) (*SGuestDHCPServer, error) return nil, fmt.Errorf("Wrong dhcp relay address") } - guestdhcp.server, guestdhcp.conn, err = dhcp.NewDHCPServer2(iface, uint16(options.HostOptions.DhcpServerPort), DEFAULT_DHCP_CLIENT_PORT) + guestdhcp.server, guestdhcp.conn, err = dhcp.NewDHCPServer2(iface, uint16(port), DEFAULT_DHCP_CLIENT_PORT) if err != nil { return nil, err } @@ -67,14 +67,19 @@ func NewGuestDHCPServer(iface string, relay []string) (*SGuestDHCPServer, error) return guestdhcp, nil } -func (s *SGuestDHCPServer) Start() { +func (s *SGuestDHCPServer) Start(blocking bool) { log.Infof("SGuestDHCPServer starting ...") - go func() { + serve := func() { err := s.server.ListenAndServe(s) if err != nil { log.Errorf("DHCP serve error: %s", err) } - }() + } + if blocking { + serve() + } else { + go serve() + } } func (s *SGuestDHCPServer) RelaySetup(addr string) error { @@ -139,6 +144,10 @@ func (s *SGuestDHCPServer) getGuestConfig(guestDesc, guestNic jsonutils.JSONObje } func (s *SGuestDHCPServer) getConfig(pkt dhcp.Packet) *dhcp.ResponseConfig { + if guestman.GuestDescGetter == nil { + return nil + } + var ( mac = pkt.CHAddr().String() ip, port = "", "" diff --git a/pkg/hostman/hostinfo/hostinfo.go b/pkg/hostman/hostinfo/hostinfo.go index 296bcdcaa7..eb79c094ca 100644 --- a/pkg/hostman/hostinfo/hostinfo.go +++ b/pkg/hostman/hostinfo/hostinfo.go @@ -117,7 +117,7 @@ func (h *SHostInfo) GetBridgeDev(bridge string) hostbridge.IBridgeDriver { func (h *SHostInfo) StartDHCPServer() { for _, nic := range h.Nics { - nic.dhcpServer.Start() + nic.dhcpServer.Start(false) } } diff --git a/pkg/hostman/hostinfo/hostinfohelper.go b/pkg/hostman/hostinfo/hostinfohelper.go index 01d8feaace..bfea90808f 100644 --- a/pkg/hostman/hostinfo/hostinfohelper.go +++ b/pkg/hostman/hostinfo/hostinfohelper.go @@ -359,7 +359,7 @@ func NewNIC(desc string) (*SNIC, error) { if nic.EnableDHCPRelay() { dhcpRelay = options.HostOptions.DhcpRelay } - nic.dhcpServer, err = hostdhcp.NewGuestDHCPServer(nic.Bridge, dhcpRelay) + nic.dhcpServer, err = hostdhcp.NewGuestDHCPServer(nic.Bridge, options.HostOptions.DhcpServerPort, dhcpRelay) if err != nil { return nil, err }