diff --git a/pkg/evpn/svi.go b/pkg/evpn/svi.go index 9db99d33..f2f0abc9 100644 --- a/pkg/evpn/svi.go +++ b/pkg/evpn/svi.go @@ -7,15 +7,12 @@ package evpn import ( "context" - "encoding/binary" "fmt" "log" - "net" "path" "sort" "github.com/google/uuid" - "github.com/vishvananda/netlink" pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" @@ -63,62 +60,14 @@ func (s *Server) CreateSvi(ctx context.Context, in *pb.CreateSviRequest) (*pb.Sv err := status.Errorf(codes.NotFound, "unable to find key %s", in.Svi.Spec.Vrf) return nil, err } - // not found, so create a new one - bridge, err := s.nLink.LinkByName(ctx, tenantbridgeName) - if err != nil { - err := status.Errorf(codes.NotFound, "unable to find key %s", tenantbridgeName) + // configure netlink + if err := s.netlinkCreateSvi(ctx, in, bridgeObject, vrf); err != nil { return nil, err } + // configure FRR vid := uint16(bridgeObject.Spec.VlanId) - // Example: bridge vlan add dev br-tenant vid self - if err := s.nLink.BridgeVlanAdd(ctx, bridge, vid, false, false, true, false); err != nil { - fmt.Printf("Failed to add vlan to bridge: %v", err) - return nil, err - } - // Example: ip link add link br-tenant name type vlan id vlanName := fmt.Sprintf("vlan%d", vid) - vlandev := &netlink.Vlan{LinkAttrs: netlink.LinkAttrs{Name: vlanName, ParentIndex: bridge.Attrs().Index}, VlanId: int(vid)} - log.Printf("Creating VLAN %v", vlandev) - if err := s.nLink.LinkAdd(ctx, vlandev); err != nil { - fmt.Printf("Failed to create vlan link: %v", err) - return nil, err - } - // Example: ip link set addr aa:bb:cc:00:00:41 - if len(in.Svi.Spec.MacAddress) > 0 { - if err := s.nLink.LinkSetHardwareAddr(ctx, vlandev, in.Svi.Spec.MacAddress); err != nil { - fmt.Printf("Failed to set MAC on link: %v", err) - return nil, err - } - } - // Example: ip address add dev - for _, gwip := range in.Svi.Spec.GwIpPrefix { - fmt.Printf("Assign the GW IP address %v to the SVI interface %v", gwip, vlandev) - myip := make(net.IP, 4) - binary.BigEndian.PutUint32(myip, gwip.Addr.GetV4Addr()) - addr := &netlink.Addr{IPNet: &net.IPNet{IP: myip, Mask: net.CIDRMask(int(gwip.Len), 32)}} - if err := s.nLink.AddrAdd(ctx, vlandev, addr); err != nil { - fmt.Printf("Failed to set IP on link: %v", err) - return nil, err - } - } - // get net device by name vrfName := path.Base(vrf.Name) - vrfdev, err := s.nLink.LinkByName(ctx, vrfName) - if err != nil { - err := status.Errorf(codes.NotFound, "unable to find key %s", vrf.Name) - return nil, err - } - // Example: ip link set master up - if err := s.nLink.LinkSetMaster(ctx, vlandev, vrfdev); err != nil { - fmt.Printf("Failed to add vlandev to vrf: %v", err) - return nil, err - } - // Example: ip link set up - if err := s.nLink.LinkSetUp(ctx, vlandev); err != nil { - fmt.Printf("Failed to up link: %v", err) - return nil, err - } - // configure FRR if err := s.frrCreateSviRequest(ctx, in, vrfName, vlanName); err != nil { return nil, err } diff --git a/pkg/evpn/svi_netlink.go b/pkg/evpn/svi_netlink.go new file mode 100644 index 00000000..5535292b --- /dev/null +++ b/pkg/evpn/svi_netlink.go @@ -0,0 +1,80 @@ +// 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) netlinkCreateSvi(ctx context.Context, in *pb.CreateSviRequest, bridgeObject *pb.LogicalBridge, vrf *pb.Vrf) error { + bridge, err := s.nLink.LinkByName(ctx, tenantbridgeName) + if err != nil { + err := status.Errorf(codes.NotFound, "unable to find key %s", tenantbridgeName) + return err + } + vid := uint16(bridgeObject.Spec.VlanId) + // Example: bridge vlan add dev br-tenant vid self + if err := s.nLink.BridgeVlanAdd(ctx, bridge, vid, false, false, true, false); err != nil { + fmt.Printf("Failed to add vlan to bridge: %v", err) + return err + } + // Example: ip link add link br-tenant name type vlan id + vlanName := fmt.Sprintf("vlan%d", vid) + vlandev := &netlink.Vlan{LinkAttrs: netlink.LinkAttrs{Name: vlanName, ParentIndex: bridge.Attrs().Index}, VlanId: int(vid)} + log.Printf("Creating VLAN %v", vlandev) + if err := s.nLink.LinkAdd(ctx, vlandev); err != nil { + fmt.Printf("Failed to create vlan link: %v", err) + return err + } + // Example: ip link set addr aa:bb:cc:00:00:41 + if len(in.Svi.Spec.MacAddress) > 0 { + if err := s.nLink.LinkSetHardwareAddr(ctx, vlandev, in.Svi.Spec.MacAddress); err != nil { + fmt.Printf("Failed to set MAC on link: %v", err) + return err + } + } + // Example: ip address add dev + for _, gwip := range in.Svi.Spec.GwIpPrefix { + fmt.Printf("Assign the GW IP address %v to the SVI interface %v", gwip, vlandev) + myip := make(net.IP, 4) + binary.BigEndian.PutUint32(myip, gwip.Addr.GetV4Addr()) + addr := &netlink.Addr{IPNet: &net.IPNet{IP: myip, Mask: net.CIDRMask(int(gwip.Len), 32)}} + if err := s.nLink.AddrAdd(ctx, vlandev, addr); err != nil { + fmt.Printf("Failed to set IP on link: %v", err) + return err + } + } + // get net device by name + vrfName := path.Base(vrf.Name) + vrfdev, err := s.nLink.LinkByName(ctx, vrfName) + if err != nil { + err := status.Errorf(codes.NotFound, "unable to find key %s", vrf.Name) + return err + } + // Example: ip link set master up + if err := s.nLink.LinkSetMaster(ctx, vlandev, vrfdev); err != nil { + fmt.Printf("Failed to add vlandev to vrf: %v", err) + return err + } + // Example: ip link set up + if err := s.nLink.LinkSetUp(ctx, vlandev); err != nil { + fmt.Printf("Failed to up link: %v", err) + return err + } + return nil +}