Skip to content

Commit

Permalink
refactor(vrf): move netlink to a separate file
Browse files Browse the repository at this point in the history
Signed-off-by: Boris Glimcher <Boris.Glimcher@emc.com>
  • Loading branch information
glimchb committed Oct 17, 2023
1 parent eb4f214 commit 7b07d38
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 132 deletions.
137 changes: 5 additions & 132 deletions pkg/evpn/vrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@ package evpn

import (
"context"
"encoding/binary"
"fmt"
"log"
"math"
"net"
"path"
"sort"

"github.com/google/uuid"
"github.com/vishvananda/netlink"

pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go"

Expand Down Expand Up @@ -52,91 +49,20 @@ func (s *Server) CreateVrf(ctx context.Context, in *pb.CreateVrfRequest) (*pb.Vr
log.Printf("Already existing Vrf with id %v", in.Vrf.Name)
return obj, nil
}
// not found, so create a new one
vrfName := resourceID
// TODO: consider choosing random table ID
tableID := uint32(1000)
if in.Vrf.Spec.Vni != nil {
tableID = uint32(1001 + math.Mod(float64(*in.Vrf.Spec.Vni), 10.0))
}
// Example: ip link add blue type vrf table 1000
vrf := &netlink.Vrf{LinkAttrs: netlink.LinkAttrs{Name: vrfName}, Table: tableID}
log.Printf("Creating VRF %v", vrf)
if err := s.nLink.LinkAdd(ctx, vrf); err != nil {
fmt.Printf("Failed to create VRF link: %v", err)
return nil, err
}
// Example: ip link set blue up
if err := s.nLink.LinkSetUp(ctx, vrf); err != nil {
fmt.Printf("Failed to up VRF link: %v", err)
return nil, err
}
// Example: ip address add <vrf-loopback> dev <vrf-name>
if in.Vrf.Spec.LoopbackIpPrefix != nil && in.Vrf.Spec.LoopbackIpPrefix.Addr != nil && in.Vrf.Spec.LoopbackIpPrefix.Len > 0 {
myip := make(net.IP, 4)
binary.BigEndian.PutUint32(myip, in.Vrf.Spec.LoopbackIpPrefix.Addr.GetV4Addr())
addr := &netlink.Addr{IPNet: &net.IPNet{IP: myip, Mask: net.CIDRMask(int(in.Vrf.Spec.LoopbackIpPrefix.Len), 32)}}
if err := s.nLink.AddrAdd(ctx, vrf, addr); err != nil {
fmt.Printf("Failed to set IP on VRF link: %v", err)
return nil, err
}
}
// TODO: Add low-prio default route. Otherwise a miss leads to lookup in the next higher table
// Example: ip route add throw default table <routing-table-number> proto evpn-gw-br metric 9999

// generate random mac, since it is not part of user facing API
mac, err := generateRandMAC()
if err != nil {
fmt.Printf("Failed to generate random MAC: %v", err)
return nil, err
}

// create bridge and vxlan only if VNI value is not empty
if in.Vrf.Spec.Vni != nil {
// Example: ip link add br100 type bridge
bridgeName := fmt.Sprintf("br%d", *in.Vrf.Spec.Vni)
bridge := &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: bridgeName}}
log.Printf("Creating Linux Bridge %v", bridge)
if err := s.nLink.LinkAdd(ctx, bridge); err != nil {
fmt.Printf("Failed to create Bridge link: %v", err)
return nil, err
}
// Example: ip link set br100 master blue addrgenmode none
if err := s.nLink.LinkSetMaster(ctx, bridge, vrf); err != nil {
fmt.Printf("Failed to add Bridge to VRF: %v", err)
return nil, err
}
// Example: ip link set br100 addr aa:bb:cc:00:00:02
if err := s.nLink.LinkSetHardwareAddr(ctx, bridge, mac); err != nil {
fmt.Printf("Failed to set MAC on Bridge link: %v", err)
return nil, err
}
// Example: ip link set br100 up
if err := s.nLink.LinkSetUp(ctx, bridge); err != nil {
fmt.Printf("Failed to up Bridge link: %v", err)
return nil, err
}
// Example: ip link add vni100 type vxlan local 10.0.0.4 dstport 4789 id 100 nolearning
vxlanName := fmt.Sprintf("vni%d", *in.Vrf.Spec.Vni)
myip := make(net.IP, 4)
binary.BigEndian.PutUint32(myip, in.Vrf.Spec.VtepIpPrefix.Addr.GetV4Addr())
// TODO: take Port from proto instead of hard-coded
vxlan := &netlink.Vxlan{LinkAttrs: netlink.LinkAttrs{Name: vxlanName}, VxlanId: int(*in.Vrf.Spec.Vni), Port: 4789, Learning: false, SrcAddr: myip}
log.Printf("Creating VXLAN %v", vxlan)
if err := s.nLink.LinkAdd(ctx, vxlan); err != nil {
fmt.Printf("Failed to create Vxlan link: %v", err)
return nil, err
}
// Example: ip link set vni100 master br100 addrgenmode none
if err := s.nLink.LinkSetMaster(ctx, vxlan, bridge); err != nil {
fmt.Printf("Failed to add Vxlan to bridge: %v", err)
return nil, err
}
// Example: ip link set vni100 up
if err := s.nLink.LinkSetUp(ctx, vxlan); err != nil {
fmt.Printf("Failed to up Vxlan link: %v", err)
return nil, err
}
// configure netlink
if err := s.netlinkCreateVrf(ctx, in, tableID, mac); err != nil {
return nil, err
}
// configure FRR
if err := s.frrCreateVrfRequest(ctx, in); err != nil {
Expand Down Expand Up @@ -164,61 +90,8 @@ func (s *Server) DeleteVrf(ctx context.Context, in *pb.DeleteVrfRequest) (*empty
err := status.Errorf(codes.NotFound, "unable to find key %s", in.Name)
return nil, err
}
// delete bridge and vxlan only if VNI value is not empty
if obj.Spec.Vni != nil {
// use netlink to find VXLAN device
vxlanName := fmt.Sprintf("vni%d", *obj.Spec.Vni)
vxlandev, err := s.nLink.LinkByName(ctx, vxlanName)
log.Printf("Deleting VXLAN %v", vxlandev)
if err != nil {
err := status.Errorf(codes.NotFound, "unable to find key %s", vxlanName)
return nil, err
}
// bring link down
if err := s.nLink.LinkSetDown(ctx, vxlandev); err != nil {
fmt.Printf("Failed to up link: %v", err)
return nil, err
}
// use netlink to delete VXLAN device
if err := s.nLink.LinkDel(ctx, vxlandev); err != nil {
fmt.Printf("Failed to delete link: %v", err)
return nil, err
}
// use netlink to find BRIDGE device
bridgeName := fmt.Sprintf("br%d", *obj.Spec.Vni)
bridgedev, err := s.nLink.LinkByName(ctx, bridgeName)
log.Printf("Deleting BRIDGE %v", bridgedev)
if err != nil {
err := status.Errorf(codes.NotFound, "unable to find key %s", bridgeName)
return nil, err
}
// bring link down
if err := s.nLink.LinkSetDown(ctx, bridgedev); err != nil {
fmt.Printf("Failed to up link: %v", err)
return nil, err
}
// use netlink to delete BRIDGE device
if err := s.nLink.LinkDel(ctx, bridgedev); err != nil {
fmt.Printf("Failed to delete link: %v", err)
return nil, err
}
}
resourceID := path.Base(obj.Name)
// use netlink to find VRF
vrf, err := s.nLink.LinkByName(ctx, resourceID)
log.Printf("Deleting VRF %v", vrf)
if err != nil {
err := status.Errorf(codes.NotFound, "unable to find key %s", resourceID)
return nil, err
}
// bring link down
if err := s.nLink.LinkSetDown(ctx, vrf); err != nil {
fmt.Printf("Failed to up link: %v", err)
return nil, err
}
// use netlink to delete VRF
if err := s.nLink.LinkDel(ctx, vrf); err != nil {
fmt.Printf("Failed to delete link: %v", err)
// configure netlink
if err := s.netlinkDeleteVrf(ctx, obj); err != nil {
return nil, err
}
// delete from FRR
Expand Down
160 changes: 160 additions & 0 deletions pkg/evpn/vrf_netlink.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries.
// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries.

// Package evpn is the main package of the application
package evpn

import (
"context"
"encoding/binary"
"fmt"
"log"
"net"
"path"

"github.com/vishvananda/netlink"

pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

func (s *Server) netlinkCreateVrf(ctx context.Context, in *pb.CreateVrfRequest, tableID uint32, mac []byte) error {
vrfName := path.Base(in.Vrf.Name)
// Example: ip link add blue type vrf table 1000
vrf := &netlink.Vrf{LinkAttrs: netlink.LinkAttrs{Name: vrfName}, Table: tableID}
log.Printf("Creating VRF %v", vrf)
if err := s.nLink.LinkAdd(ctx, vrf); err != nil {
fmt.Printf("Failed to create VRF link: %v", err)
return err
}
// Example: ip link set blue up
if err := s.nLink.LinkSetUp(ctx, vrf); err != nil {
fmt.Printf("Failed to up VRF link: %v", err)
return err
}
// Example: ip address add <vrf-loopback> dev <vrf-name>
if in.Vrf.Spec.LoopbackIpPrefix != nil && in.Vrf.Spec.LoopbackIpPrefix.Addr != nil && in.Vrf.Spec.LoopbackIpPrefix.Len > 0 {
myip := make(net.IP, 4)
binary.BigEndian.PutUint32(myip, in.Vrf.Spec.LoopbackIpPrefix.Addr.GetV4Addr())
addr := &netlink.Addr{IPNet: &net.IPNet{IP: myip, Mask: net.CIDRMask(int(in.Vrf.Spec.LoopbackIpPrefix.Len), 32)}}
if err := s.nLink.AddrAdd(ctx, vrf, addr); err != nil {
fmt.Printf("Failed to set IP on VRF link: %v", err)
return err
}
}
// TODO: Add low-prio default route. Otherwise a miss leads to lookup in the next higher table
// Example: ip route add throw default table <routing-table-number> proto evpn-gw-br metric 9999

// create bridge and vxlan only if VNI value is not empty
if in.Vrf.Spec.Vni != nil {
// Example: ip link add br100 type bridge
bridgeName := fmt.Sprintf("br%d", *in.Vrf.Spec.Vni)
bridge := &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: bridgeName}}
log.Printf("Creating Linux Bridge %v", bridge)
if err := s.nLink.LinkAdd(ctx, bridge); err != nil {
fmt.Printf("Failed to create Bridge link: %v", err)
return err
}
// Example: ip link set br100 master blue addrgenmode none
if err := s.nLink.LinkSetMaster(ctx, bridge, vrf); err != nil {
fmt.Printf("Failed to add Bridge to VRF: %v", err)
return err
}
// Example: ip link set br100 addr aa:bb:cc:00:00:02
if err := s.nLink.LinkSetHardwareAddr(ctx, bridge, mac); err != nil {
fmt.Printf("Failed to set MAC on Bridge link: %v", err)
return err
}
// Example: ip link set br100 up
if err := s.nLink.LinkSetUp(ctx, bridge); err != nil {
fmt.Printf("Failed to up Bridge link: %v", err)
return err
}
// Example: ip link add vni100 type vxlan local 10.0.0.4 dstport 4789 id 100 nolearning
vxlanName := fmt.Sprintf("vni%d", *in.Vrf.Spec.Vni)
myip := make(net.IP, 4)
binary.BigEndian.PutUint32(myip, in.Vrf.Spec.VtepIpPrefix.Addr.GetV4Addr())
// TODO: take Port from proto instead of hard-coded
vxlan := &netlink.Vxlan{LinkAttrs: netlink.LinkAttrs{Name: vxlanName}, VxlanId: int(*in.Vrf.Spec.Vni), Port: 4789, Learning: false, SrcAddr: myip}
log.Printf("Creating VXLAN %v", vxlan)
if err := s.nLink.LinkAdd(ctx, vxlan); err != nil {
fmt.Printf("Failed to create Vxlan link: %v", err)
return err
}
// Example: ip link set vni100 master br100 addrgenmode none
if err := s.nLink.LinkSetMaster(ctx, vxlan, bridge); err != nil {
fmt.Printf("Failed to add Vxlan to bridge: %v", err)
return err
}
// Example: ip link set vni100 up
if err := s.nLink.LinkSetUp(ctx, vxlan); err != nil {
fmt.Printf("Failed to up Vxlan link: %v", err)
return err
}
}
return nil
}

func (s *Server) netlinkDeleteVrf(ctx context.Context, obj *pb.Vrf) error {
// delete bridge and vxlan only if VNI value is not empty
if obj.Spec.Vni != nil {
// use netlink to find VXLAN device
vxlanName := fmt.Sprintf("vni%d", *obj.Spec.Vni)
vxlandev, err := s.nLink.LinkByName(ctx, vxlanName)
log.Printf("Deleting VXLAN %v", vxlandev)
if err != nil {
err := status.Errorf(codes.NotFound, "unable to find key %s", vxlanName)
return err
}
// bring link down
if err := s.nLink.LinkSetDown(ctx, vxlandev); err != nil {
fmt.Printf("Failed to up link: %v", err)
return err
}
// use netlink to delete VXLAN device
if err := s.nLink.LinkDel(ctx, vxlandev); err != nil {
fmt.Printf("Failed to delete link: %v", err)
return err
}
// use netlink to find BRIDGE device
bridgeName := fmt.Sprintf("br%d", *obj.Spec.Vni)
bridgedev, err := s.nLink.LinkByName(ctx, bridgeName)
log.Printf("Deleting BRIDGE %v", bridgedev)
if err != nil {
err := status.Errorf(codes.NotFound, "unable to find key %s", bridgeName)
return err
}
// bring link down
if err := s.nLink.LinkSetDown(ctx, bridgedev); err != nil {
fmt.Printf("Failed to up link: %v", err)
return err
}
// use netlink to delete BRIDGE device
if err := s.nLink.LinkDel(ctx, bridgedev); err != nil {
fmt.Printf("Failed to delete link: %v", err)
return err
}
}
vrfName := path.Base(obj.Name)
// use netlink to find VRF
vrf, err := s.nLink.LinkByName(ctx, vrfName)
log.Printf("Deleting VRF %v", vrf)
if err != nil {
err := status.Errorf(codes.NotFound, "unable to find key %s", vrfName)
return err
}
// bring link down
if err := s.nLink.LinkSetDown(ctx, vrf); err != nil {
fmt.Printf("Failed to up link: %v", err)
return err
}
// use netlink to delete VRF
if err := s.nLink.LinkDel(ctx, vrf); err != nil {
fmt.Printf("Failed to delete link: %v", err)
return err
}
return nil
}

0 comments on commit 7b07d38

Please sign in to comment.