Skip to content

Commit

Permalink
Merge branch 'master' into add-agentx-for-sonic
Browse files Browse the repository at this point in the history
  • Loading branch information
robertvolkmann authored Oct 22, 2024
2 parents ea346a2 + dcbe18b commit affd383
Show file tree
Hide file tree
Showing 49 changed files with 952 additions and 627 deletions.
15 changes: 8 additions & 7 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,26 @@ jobs:

steps:
- name: Log in to the container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKER_REGISTRY_USER }}
password: ${{ secrets.DOCKER_REGISTRY_TOKEN }}

- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Set up Go 1.21
uses: actions/setup-go@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.21.x'
go-version-file: 'go.mod'
cache: false

- name: Install libpcap-dev
run: sudo apt-get install -y libpcap-dev

- name: Lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v6
with:
args: --build-tags client -p bugs -p unused --timeout=3m

Expand All @@ -50,7 +51,7 @@ jobs:
[ "${GITHUB_EVENT_NAME}" == 'push' ] && echo "tag=latest" >> $GITHUB_ENV || true
- name: Build and push image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v6
with:
context: .
push: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-drafter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@v5
- uses: release-drafter/release-drafter@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
FROM golang:1.21-alpine3.18 as builder
FROM golang:1.23-alpine3.20 AS builder
WORKDIR /work
COPY . .
RUN apk add \
make \
binutils \
coreutils \
git \
gcc \
libpcap-dev \
musl-dev \
dbus-libs
RUN make

FROM alpine:3.18
FROM alpine:3.20

RUN apk add \
libpcap \
Expand Down
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ CGO_ENABLED := 1

SHA := $(shell git rev-parse --short=8 HEAD)
GITVERSION := $(shell git describe --long --all)
BUILDDATE := $(shell GO111MODULE=off go run ${COMMONDIR}/time.go)
# gnu date format iso-8601 is parsable with Go RFC3339
BUILDDATE := $(shell date --iso-8601=seconds)
VERSION := $(or ${VERSION},$(shell git describe --tags --exact-match 2> /dev/null || git symbolic-ref -q --short HEAD || git rev-parse --short HEAD))

in-docker: gofmt test all;
Expand Down Expand Up @@ -35,7 +36,7 @@ test:

.PHONY: lint
lint:
golangci-lint run --build-tags client -p bugs -p unused
golangci-lint run --build-tags client -p bugs -p unused

.PHONY: gofmt
gofmt:
Expand Down
2 changes: 2 additions & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ type Config struct {
GrpcCACertFile string `required:"false" desc:"the gRPC CA certificate file" envconfig:"grpc_ca_cert_file"`
GrpcClientCertFile string `required:"false" desc:"the gRPC client certificate file" envconfig:"grpc_client_cert_file"`
GrpcClientKeyFile string `required:"false" desc:"the gRPC client key file" envconfig:"grpc_client_key_file"`
PXEVlanID uint16 `required:"false" default:"4000" desc:"the id of the pxe vlan" envconfig:"pxe_vlan_id"`
AdditionalRouteMapCIDRs []string `required:"false" default:"10.240.0.0/12" desc:"additional route map entries, typically the pod/service CIDRs, one or more CIDR for ipv4 or ipv6, separated by comma" envconfig:"additional_route_map_cidrs"`
}
7 changes: 1 addition & 6 deletions cmd/grpc.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cmd

import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
Expand Down Expand Up @@ -48,13 +47,9 @@ func NewGrpcClient(log *slog.Logger, address string, cert, key, caCert []byte) (
dialOpts := []grpc.DialOption{
grpc.WithKeepaliveParams(kacp),
grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)),
grpc.WithBlock(),
}

ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()

conn, err := grpc.DialContext(ctx, address, dialOpts...)
conn, err := grpc.NewClient(address, dialOpts...)
if err != nil {
return nil, err
}
Expand Down
8 changes: 8 additions & 0 deletions cmd/internal/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ type Core struct {
eventServiceClient v1.EventServiceClient

metrics *metrics.Metrics

pxeVlanID uint16
additionalRouteMapCIDRs []string
}

type Config struct {
Expand All @@ -56,6 +59,9 @@ type Config struct {
EventServiceClient v1.EventServiceClient

Metrics *metrics.Metrics

PXEVlanID uint16
AdditionalRouteMapCIDRs []string
}

func New(c Config) *Core {
Expand All @@ -77,5 +83,7 @@ func New(c Config) *Core {
driver: c.Driver,
eventServiceClient: c.EventServiceClient,
metrics: c.Metrics,
pxeVlanID: c.PXEVlanID,
additionalRouteMapCIDRs: c.AdditionalRouteMapCIDRs,
}
}
97 changes: 80 additions & 17 deletions cmd/internal/core/reconfigure-switch.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package core

import (
"fmt"
"net"
"os"
"slices"
"strconv"
Expand All @@ -23,7 +24,7 @@ func (c *Core) ReconfigureSwitch() {
for range t.C {
c.log.Info("trigger reconfiguration")
start := time.Now()
err := c.reconfigureSwitch(host)
s, err := c.reconfigureSwitch(host)
elapsed := time.Since(start)
c.log.Info("reconfiguration took", "elapsed", elapsed)

Expand All @@ -32,6 +33,7 @@ func (c *Core) ReconfigureSwitch() {
ns := elapsed.Nanoseconds()
nr := &models.V1SwitchNotifyRequest{
SyncDuration: &ns,
PortStates: make(map[string]string),
}
if err != nil {
errStr := err.Error()
Expand All @@ -42,6 +44,34 @@ func (c *Core) ReconfigureSwitch() {
c.log.Info("reconfiguration succeeded")
}

// fill the port states of the switch
var nics []*models.V1SwitchNic
if s != nil {
nics = s.Nics
}
for _, n := range nics {
if n == nil || n.Name == nil {
// lets log the whole nic because the name could be empty; lets hope there is some useful information
// in the nic
c.log.Error("could not check if link is up", "nic", n)
c.metrics.CountError("switch-reconfiguration")
continue
}
isup, err := isLinkUp(*n.Name)
if err != nil {
c.log.Error("could not check if link is up", "error", err, "nicname", *n.Name)
nr.PortStates[*n.Name] = models.V1SwitchNicActualUNKNOWN
c.metrics.CountError("switch-reconfiguration")
continue
}
if isup {
nr.PortStates[*n.Name] = models.V1SwitchNicActualUP
} else {
nr.PortStates[*n.Name] = models.V1SwitchNicActualDOWN
}

}

params.Body = nr
_, err = c.driver.SwitchOperations().NotifySwitch(params, nil)
if err != nil {
Expand All @@ -51,63 +81,76 @@ func (c *Core) ReconfigureSwitch() {
}
}

func (c *Core) reconfigureSwitch(switchName string) error {
func (c *Core) reconfigureSwitch(switchName string) (*models.V1SwitchResponse, error) {
params := sw.NewFindSwitchParams()
params.ID = switchName
fsr, err := c.driver.SwitchOperations().FindSwitch(params, nil)
if err != nil {
return fmt.Errorf("could not fetch switch from metal-api: %w", err)
return nil, fmt.Errorf("could not fetch switch from metal-api: %w", err)
}

s := fsr.Payload
switchConfig, err := c.buildSwitcherConfig(s)
if err != nil {
return fmt.Errorf("could not build switcher config: %w", err)
return nil, fmt.Errorf("could not build switcher config: %w", err)
}

err = fillEth0Info(switchConfig, c.managementGateway)
if err != nil {
return fmt.Errorf("could not gather information about eth0 nic: %w", err)
return nil, fmt.Errorf("could not gather information about eth0 nic: %w", err)
}

c.log.Debug("assembled new config for switch", "config", switchConfig)
if !c.enableReconfigureSwitch {
c.log.Debug("skip config application because of environment setting")
return nil
return s, nil
}

err = c.nos.Apply(switchConfig)
if err != nil {
return fmt.Errorf("could not apply switch config: %w", err)
return nil, fmt.Errorf("could not apply switch config: %w", err)
}

return nil
return s, nil
}

func (c *Core) buildSwitcherConfig(s *models.V1SwitchResponse) (*types.Conf, error) {
asn64, err := strconv.ParseUint(c.asn, 10, 32)
asn := uint32(asn64)
if err != nil {
return nil, err
}
if c.pxeVlanID >= vlan.VlanIDMin && c.pxeVlanID <= vlan.VlanIDMax {
return nil, fmt.Errorf("configured PXE VLAN ID is in the reserved area of %d, %d", vlan.VlanIDMin, vlan.VlanIDMax)
}

switcherConfig := &types.Conf{
Name: s.Name,
LogLevel: mapLogLevel(c.logLevel),
ASN: asn,
Loopback: c.loopbackIP,
MetalCoreCIDR: c.cidr,
AdditionalBridgeVIDs: c.additionalBridgeVIDs,
Name: s.Name,
LogLevel: mapLogLevel(c.logLevel),
ASN: uint32(asn64), // nolint:gosec
Loopback: c.loopbackIP,
MetalCoreCIDR: c.cidr,
AdditionalBridgeVIDs: c.additionalBridgeVIDs,
PXEVlanID: c.pxeVlanID,
AdditionalRouteMapCIDRs: c.additionalRouteMapCIDRs,
}

p := types.Ports{
Underlay: c.spineUplinks,
Unprovisioned: []string{},
Vrfs: map[string]*types.Vrf{},
Firewalls: map[string]*types.Firewall{},
DownPorts: map[string]bool{},
}
p.BladePorts = c.additionalBridgePorts
for _, nic := range s.Nics {
port := *nic.Name

if isPortStatusEqual(models.V1SwitchNicActualDOWN, nic.Actual) {
if has := p.DownPorts[port]; !has {
p.DownPorts[port] = true
}
}

if slices.Contains(p.Underlay, port) {
continue
}
Expand Down Expand Up @@ -142,7 +185,7 @@ func (c *Core) buildSwitcherConfig(s *models.V1SwitchResponse) (*types.Conf, err
if err != nil {
return nil, err
}
vrf.VNI = uint32(vni64)
vrf.VNI = uint32(vni64) // nolint:gosec
vrf.Neighbors = append(vrf.Neighbors, port)
if nic.Filter != nil {
vrf.Cidrs = nic.Filter.Cidrs
Expand All @@ -152,7 +195,10 @@ func (c *Core) buildSwitcherConfig(s *models.V1SwitchResponse) (*types.Conf, err
switcherConfig.Ports = p

c.nos.SanitizeConfig(switcherConfig)
switcherConfig.FillRouteMapsAndIPPrefixLists()
err = switcherConfig.FillRouteMapsAndIPPrefixLists()
if err != nil {
return nil, err
}
m, err := vlan.ReadMapping()
if err != nil {
return nil, err
Expand Down Expand Up @@ -202,3 +248,20 @@ func fillEth0Info(c *types.Conf, gw string) error {
c.Ports.Eth0.Gateway = gw
return nil
}

// isLinkUp checks if the interface with the given name is up.
// It returns a boolean indicating if the interface is up, and an error if there was a problem checking the interface.
func isLinkUp(nicname string) (bool, error) {
nic, err := net.InterfaceByName(nicname)
if err != nil {
return false, fmt.Errorf("cannot query interface %q : %w", nicname, err)
}
return nic.Flags&net.FlagUp != 0, nil
}

func isPortStatusEqual(stat string, other *string) bool {
if other == nil {
return false
}
return strings.EqualFold(stat, *other)
}
Loading

0 comments on commit affd383

Please sign in to comment.