Skip to content

Commit

Permalink
Golang versioned ovn-kube-util (#113)
Browse files Browse the repository at this point in the history

Signed-off-by: Pengfei Ni <feiskyer@gmail.com>
  • Loading branch information
feiskyer authored and shettyg committed May 2, 2017
1 parent c304ae4 commit 5aef7f4
Show file tree
Hide file tree
Showing 101 changed files with 19,991 additions and 0 deletions.
1 change: 1 addition & 0 deletions go-controller/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export OUT_DIR

all build:
hack/build-go.sh cmd/ovnkube/ovnkube.go
hack/build-go.sh cmd/ovn-kube-util/ovn-kube-util.go
cp -f pkg/cluster/bin/ovnkube-setup-* ${OUT_DIR}/go/bin/

install:
Expand Down
113 changes: 113 additions & 0 deletions go-controller/cmd/ovn-kube-util/app/netlink.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package app

import (
"net"
"syscall"

"github.com/vishvananda/netlink"
"github.com/vishvananda/netlink/nl"
)

// addrList gets netlink.Addr for specified netlink.Link.
// TODO: remove this after https://github.com/vishvananda/netlink/pull/226 is merged.
func addrList(link netlink.Link, family int) ([]netlink.Addr, error) {
h := &netlink.Handle{}
req := nl.NewNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family)
req.AddData(msg)

msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
if err != nil {
return nil, err
}

indexFilter := 0
if link != nil {
base := link.Attrs()

// ensure index
if base != nil && base.Index == 0 {
newlink, _ := h.LinkByName(base.Name)
if newlink != nil {
base.Index = newlink.Attrs().Index
}
}
indexFilter = base.Index
}

var res []netlink.Addr
for _, m := range msgs {
addr, msgFamily, ifindex, err := parseAddr(m)
if err != nil {
return res, err
}

if link != nil && ifindex != indexFilter {
// Ignore messages from other interfaces
continue
}

if family != netlink.FAMILY_ALL && msgFamily != family {
continue
}

res = append(res, addr)
}

return res, nil
}

// parseAddr parses netlink.Addr from netlink message.
func parseAddr(m []byte) (addr netlink.Addr, family, index int, err error) {
msg := nl.DeserializeIfAddrmsg(m)

family = -1
index = -1

attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
if err1 != nil {
err = err1
return
}

family = int(msg.Family)
index = int(msg.Index)

var local, dst *net.IPNet
for _, attr := range attrs {
switch attr.Attr.Type {
case syscall.IFA_ADDRESS:
dst = &net.IPNet{
IP: attr.Value,
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
}
addr.Peer = dst
case syscall.IFA_LOCAL:
local = &net.IPNet{
IP: attr.Value,
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
}
addr.IPNet = local
case syscall.IFA_BROADCAST:
addr.Broadcast = attr.Value
case syscall.IFA_LABEL:
addr.Label = string(attr.Value[:len(attr.Value)-1])
case netlink.IFA_FLAGS:
addr.Flags = int(nl.NativeEndian().Uint32(attr.Value[0:4]))
case nl.IFA_CACHEINFO:
ci := nl.DeserializeIfaCacheInfo(attr.Value)
addr.PreferedLft = int(ci.IfaPrefered)
addr.ValidLft = int(ci.IfaValid)
}
}

// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
if local != nil {
addr.IPNet = local
} else {
addr.IPNet = dst
}
addr.Scope = int(msg.Scope)

return
}
135 changes: 135 additions & 0 deletions go-controller/cmd/ovn-kube-util/app/nics-to-bridge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package app

import (
"fmt"
"os"
"strings"
"syscall"

"github.com/Sirupsen/logrus"
"github.com/urfave/cli"
"github.com/vishvananda/netlink"
"k8s.io/apimachinery/pkg/util/errors"

"github.com/openvswitch/ovn-kubernetes/go-controller/pkg/util"
)

// NicsToBridgeCommand creates ovs bridge for provided nic interfaces.
var NicsToBridgeCommand = cli.Command{
Name: "nics-to-bridge",
Usage: "Create ovs bridge for nic interfaces",
Flags: []cli.Flag{},
Action: func(context *cli.Context) error {
args := context.Args()
if len(args) == 0 {
return fmt.Errorf("Please specify list of nic interfaces")
}

var errorList []error
for _, nic := range args {
if err := nicToBridge(nic); err != nil {
errorList = append(errorList, err)
}
}

return errors.NewAggregate(errorList)
},
}

func getBridgeName(iface string) string {
return fmt.Sprintf("br%s", iface)
}

func saveIPAddress(iface, bridge netlink.Link, addrs []netlink.Addr) error {
for i := range addrs {
addr := addrs[i]

// Remove from old interface
if err := netlink.AddrDel(iface, &addr); err != nil {
logrus.Errorf("Remove addr from %q failed: %v", iface.Attrs().Name, err)
return err
}

// Add to ovs bridge
addr.Label = bridge.Attrs().Name
if err := netlink.AddrAdd(bridge, &addr); err != nil {
logrus.Errorf("Add addr to bridge %q failed: %v", bridge.Attrs().Name, err)
return err
}
logrus.Infof("Successfully saved addr %q to bridge %q", addr.String(), bridge.Attrs().Name)
}

return netlink.LinkSetUp(bridge)
}

func saveRoute(iface, bridge netlink.Link, routes []netlink.Route) error {
for i := range routes {
route := routes[i]

// Remove from old interface
if err := netlink.RouteDel(&route); err != nil && !strings.Contains(err.Error(), "no such process") {
logrus.Errorf("Remove route from %q failed: %v", iface.Attrs().Name, err)
return err
}

// Add to ovs bridge
route.LinkIndex = bridge.Attrs().Index
if err := netlink.RouteAdd(&route); err != nil && !os.IsExist(err) {
logrus.Errorf("Add route to bridge %q failed: %v", bridge.Attrs().Name, err)
return err
}

logrus.Infof("Successfully saved route %q", route.String())
}

return nil
}

func nicToBridge(iface string) error {
ifaceLink, err := netlink.LinkByName(iface)
if err != nil {
return err
}

bridge := getBridgeName(iface)
stdout, stderr, err := util.RunOVSVsctl(
"--", "--may-exist", "add-br", bridge,
"--", "br-set-external-id", bridge, "bridge-id", bridge,
"--", "set", "bridge", bridge, "fail-mode=standalone",
fmt.Sprintf("other_config:hwaddr=%s", ifaceLink.Attrs().HardwareAddr),
"--", "add-port", bridge, iface)
if err != nil {
logrus.Errorf("Failed to create OVS bridge, stdout: %q, stderr: %q, error: %v", stdout, stderr, err)
return err
}
logrus.Infof("Successfully created OVS bridge %q", bridge)

// Get ip addresses and routes before any real operations.
// Note: addrList is a workround for also getting broadcast addr.
// TODO: switch to netlink.AddrList after https://github.com/vishvananda/netlink/pull/226 is merged.
addrs, err := addrList(ifaceLink, syscall.AF_INET)
if err != nil {
return err
}
routes, err := netlink.RouteList(ifaceLink, syscall.AF_INET)
if err != nil {
return err
}

bridgeLink, err := netlink.LinkByName(bridge)
if err != nil {
return err
}

// save ip addresses to bridge.
if err = saveIPAddress(ifaceLink, bridgeLink, addrs); err != nil {
return err
}

// save routes to bridge.
if err = saveRoute(ifaceLink, bridgeLink, routes); err != nil {
return err
}

return nil
}
24 changes: 24 additions & 0 deletions go-controller/cmd/ovn-kube-util/ovn-kube-util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"os"

"github.com/Sirupsen/logrus"
"github.com/openvswitch/ovn-kubernetes/go-controller/cmd/ovn-kube-util/app"
"github.com/urfave/cli"
)

func main() {
c := cli.NewApp()
c.Name = "ovn-kube-util"
c.Usage = "Utils for kubernetes ovn"
c.Version = "0.0.1"

c.Commands = []cli.Command{
app.NicsToBridgeCommand,
}

if err := c.Run(os.Args); err != nil {
logrus.Fatal(err)
}
}
31 changes: 31 additions & 0 deletions go-controller/pkg/util/ovs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package util

import (
"bytes"
"fmt"
"os/exec"
)

const (
ovsCommandTimeout = 5
ovsVsctlCommand = "ovs-vsctl"
)

// RunOVSVsctl runs a command via ovs-vsctl.
func RunOVSVsctl(args ...string) (string, string, error) {
cmdPath, err := exec.LookPath(ovsVsctlCommand)
if err != nil {
return "", "", err
}

stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
cmdArgs := []string{fmt.Sprintf("--timeout=%d", ovsCommandTimeout)}
cmdArgs = append(cmdArgs, args...)
cmd := exec.Command(cmdPath, cmdArgs...)
cmd.Stdout = stdout
cmd.Stderr = stderr

err = cmd.Run()
return stdout.String(), stderr.String(), err
}
Loading

0 comments on commit 5aef7f4

Please sign in to comment.