Merge pull request #4929 from yousong/bugfix/yousong-iproute2

hostman: replace route command dep with netlink call
This commit is contained in:
yunion-ci-robot
2020-01-16 21:24:11 +08:00
committed by GitHub
5 changed files with 186 additions and 65 deletions
+26 -24
View File
@@ -29,7 +29,6 @@ import (
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/iproute2"
"yunion.io/x/onecloud/pkg/util/netutils2"
"yunion.io/x/onecloud/pkg/util/procutils"
)
type IBridgeDriver interface {
@@ -193,14 +192,21 @@ func (d *SBaseBridgeDriver) SetupAddresses(mask net.IPMask) error {
return errors.Wrapf(err, "set bridge %s address", br)
}
}
if options.HostOptions.TunnelPaddingBytes > 0 {
mtu := 1500 + int(options.HostOptions.TunnelPaddingBytes)
if err := iproute2.NewLink(br).MTU(mtu).Err(); err != nil {
return errors.Wrapf(err, "setting bridge %s mtu %d", br, mtu)
{
brLink := iproute2.NewLink(br).Up()
if options.HostOptions.TunnelPaddingBytes > 0 {
mtu := 1500 + int(options.HostOptions.TunnelPaddingBytes)
brLink.MTU(mtu)
}
if err := brLink.Err(); err != nil {
return errors.Wrapf(err, "setting bridge %s up", br)
}
}
if d.inter != nil {
ifname := d.inter.String()
if err := iproute2.NewAddress(ifname).Exact().Err(); err != nil {
return errors.Wrapf(err, "remove addresses on slave ifname: %s", ifname)
}
if err := iproute2.NewLink(ifname).Up().Err(); err != nil {
return errors.Wrapf(err, "setting bridge %s ifname %s up", br, ifname)
}
@@ -209,30 +215,26 @@ func (d *SBaseBridgeDriver) SetupAddresses(mask net.IPMask) error {
}
func (d *SBaseBridgeDriver) SetupSlaveAddresses(slaveAddrs [][]string) error {
for _, slaveAddr := range slaveAddrs {
if err := iproute2.NewAddress(d.inter.String()).Exact().Err(); err != nil {
return errors.Wrap(err, "remove address on slave interface")
}
addr := fmt.Sprintf("%s/%s", slaveAddr[0], slaveAddr[1])
if err := iproute2.NewAddress(d.bridge.String(), addr).Add().Err(); err != nil {
return errors.Wrap(err, "move address to bridge interface")
}
br := d.bridge.String()
addrs := make([]string, len(slaveAddrs))
for i, slaveAddr := range slaveAddrs {
addrs[i] = fmt.Sprintf("%s/%s", slaveAddr[0], slaveAddr[1])
}
if err := iproute2.NewAddress(br, addrs...).Add().Err(); err != nil {
return errors.Wrap(err, "move secondary addresses to bridge interface")
}
return nil
}
func (d *SBaseBridgeDriver) SetupRoutes(routes [][]string) error {
for _, r := range routes {
var cmd []string
if r[2] == "0.0.0.0" {
cmd = []string{"route", "add", "default", "gw", r[1], "dev", d.bridge.String()}
} else {
cmd = []string{"route", "add", "-net", r[0], "netmask", r[2], "gw", r[1], "dev", d.bridge.String()}
}
if _, err := procutils.NewCommand(cmd[0], cmd[1:]...).Output(); err != nil {
log.Errorln(err)
return fmt.Errorf("Failed to add slave address to bridge %s", d.bridge)
}
br := d.bridge.String()
r := iproute2.NewRoute(br)
for _, route := range routes {
netStr, maskStr, gwStr := route[0], route[2], route[1]
r.Add(netStr, maskStr, gwStr)
}
if err := r.Err(); err != nil {
return errors.Wrapf(err, "set routes on %s", br)
}
return nil
}
+136
View File
@@ -0,0 +1,136 @@
package iproute2
import (
"net"
"github.com/vishvananda/netlink"
"yunion.io/x/pkg/errors"
)
const (
errBadIP = errors.Error("bad ip")
)
type Route struct {
*Link
}
func NewRoute(ifname string) *Route {
l := NewLink(ifname)
route := &Route{
Link: l,
}
return route
}
func (route *Route) link() (link netlink.Link, ok bool) {
link = route.Link.link
if link != nil {
ok = true
}
return
}
func (route *Route) List4() ([]netlink.Route, error) {
link, ok := route.link()
if !ok {
return nil, route.Err()
}
rs, err := netlink.RouteList(link, netlink.FAMILY_V4)
if err != nil {
route.addErr(err, "route list")
return nil, route.Err()
}
for i := range rs {
if rs[i].Dst == nil {
// make the return value easier to work with
rs[i].Dst = &net.IPNet{
IP: net.IPv4zero,
Mask: net.IPMask(net.IPv4zero),
}
}
}
return rs, nil
}
func (route *Route) AddByIPNet(ipnet *net.IPNet, gw net.IP) *Route {
link, ok := route.link()
if !ok {
return route
}
r := &netlink.Route{
LinkIndex: link.Attrs().Index,
Dst: ipnet,
}
if len(gw) > 0 {
r.Gw = gw
}
if err := netlink.RouteReplace(r); err != nil {
route.addErr(err, "RouteReplace %s", r.String())
}
return route
}
func (route *Route) AddByCidr(cidr string, gwStr string) *Route {
var (
dst *net.IPNet
gw net.IP
err error
)
if _, dst, err = net.ParseCIDR(cidr); err != nil {
route.addErr(err, "parse cidr")
return route
}
if gwStr != "" {
gw = net.ParseIP(gwStr)
if len(gw) == 0 {
route.addErr(errBadIP, "gwStr: %s", gwStr)
return route
}
}
return route.AddByIPNet(dst, gw)
}
func (route *Route) Add(netStr, maskStr, gwStr string) *Route {
var (
ip net.IP
mask net.IPMask
gw net.IP
)
if ip = net.ParseIP(netStr); len(ip) == 0 {
route.addErr(errBadIP, "netStr %s", netStr)
return route
}
if maskIp := net.ParseIP(maskStr); len(maskIp) == 0 {
route.addErr(errBadIP, "maskStr %s", maskStr)
return route
} else {
if ip := maskIp.To4(); len(ip) > 0 {
maskIp = ip
}
mask = net.IPMask(maskIp)
ones, bits := mask.Size()
if ones == 0 && bits == 0 {
route.addErr(errBadIP, "bad mask %s", maskStr)
return route
}
}
if gwStr != "" {
if gw = net.ParseIP(gwStr); len(gw) == 0 {
route.addErr(errBadIP, "gwStr %s", gwStr)
return route
}
}
ipnet := &net.IPNet{
IP: ip,
Mask: mask,
}
return route.AddByIPNet(ipnet, gw)
}
-24
View File
@@ -19,7 +19,6 @@ import (
"fmt"
"net"
"reflect"
"regexp"
"strconv"
"strings"
"unicode"
@@ -32,7 +31,6 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/util/procutils"
"yunion.io/x/onecloud/pkg/util/regutils2"
)
var PSEUDO_VIP = "169.254.169.231"
@@ -370,28 +368,6 @@ func GetSecretInterfaceAddress() (string, int) {
return addr, SECRET_MASK_LEN
}
func (n *SNetInterface) GetRoutes(gwOnly bool) [][]string {
output, err := procutils.NewCommand("route", "-n").Output()
if err != nil {
return nil
}
return n.getRoutes(gwOnly, strings.Split(string(output), "\n"))
}
func (n *SNetInterface) getRoutes(gwOnly bool, outputs []string) [][]string {
re := regexp.MustCompile(`(?P<dest>[0-9.]+)\s+(?P<gw>[0-9.]+)\s+(?P<mask>[0-9.]+)` +
`\s+[A-Z!]+\s+[0-9]+\s+[0-9]+\s+[0-9]+\s+` + n.name)
var res [][]string = make([][]string, 0)
for _, line := range outputs {
m := regutils2.GetParams(re, line)
if len(m) > 0 && (!gwOnly || m["gw"] != "0.0.0.0") {
res = append(res, []string{m["dest"], m["gw"], m["mask"]})
}
}
return res
}
func (n *SNetInterface) GetSlaveAddresses() [][]string {
addrs := n.GetAddresses()
var slaves = make([][]string, 0)
+24
View File
@@ -30,6 +30,30 @@ func (n *SNetInterface) GetAddresses() [][]string {
return r
}
func (n *SNetInterface) GetRoutes(gwOnly bool) [][]string {
rs, err := iproute2.NewRoute(n.name).List4()
if err != nil {
return nil
}
res := [][]string{}
for i := range rs {
r := &rs[i]
ok := true
if masklen, _ := r.Dst.Mask.Size(); gwOnly && masklen != 0 {
ok = false
}
if ok {
res = append(res, []string{
r.Dst.IP.String(),
r.Gw.String(),
net.IP(r.Dst.Mask).String(),
})
}
}
return res
}
func DefaultSrcIpDev() (srcIp net.IP, ifname string, err error) {
destIp := net.ParseIP("114.114.114.114")
routes, err := netlink.RouteGet(destIp)
-17
View File
@@ -15,26 +15,9 @@
package netutils2
import (
"reflect"
"testing"
)
func TestSNetInterface_getRoutes(t *testing.T) {
n := SNetInterface{name: "br0"}
routes := []string{"Kernel IP routing table",
"Destination Gateway Genmask Flags Metric Ref Use Iface",
"0.0.0.0 10.168.222.1 0.0.0.0 UG 0 0 0 br0",
"10.168.222.0 0.0.0.0 255.255.255.0 U 0 0 0 br0",
"169.254.169.254 10.168.222.1 255.255.255.255 UGH 0 0 0 br0",
""}
want := [][]string{{"0.0.0.0", "10.168.222.1", "0.0.0.0"}, {"169.254.169.254", "10.168.222.1", "255.255.255.255"}}
if got := n.getRoutes(true, routes); !reflect.DeepEqual(got, want) {
t.Errorf("getParams() = %v, want %v", got, want)
}
}
func TestNetlen2Mask(t *testing.T) {
type args struct {
netmasklen int