diff --git a/pkg/LinuxCIModule/lci.go b/pkg/LinuxCIModule/lci.go index f73f964d..96075080 100644 --- a/pkg/LinuxCIModule/lci.go +++ b/pkg/LinuxCIModule/lci.go @@ -7,6 +7,7 @@ package linuxcimodule import ( "context" + "fmt" // "io/ioutil" "log" @@ -48,6 +49,7 @@ func handlebp(objectData *eventbus.ObjectData) { log.Printf("LCI : GetBP error: %s\n", err) comp.Name = lciComp comp.CompStatus = common.ComponentStatusError + comp.Details = fmt.Sprintf("LCI : GetBP error: %s\n", err) if comp.Timer == 0 { comp.Timer = 2 * time.Second } else { @@ -63,6 +65,7 @@ func handlebp(objectData *eventbus.ObjectData) { log.Printf("LVM: Mismatch in resoruce version %+v\n and bp resource version %+v\n", objectData.ResourceVersion, BP.ResourceVersion) comp.Name = lciComp comp.CompStatus = common.ComponentStatusError + comp.Details = fmt.Sprintf("LVM: Mismatch in resoruce version %+v\n and bp resource version %+v\n", objectData.ResourceVersion, BP.ResourceVersion) if comp.Timer == 0 { comp.Timer = 2 * time.Second } else { @@ -82,10 +85,10 @@ func handlebp(objectData *eventbus.ObjectData) { } } if BP.Status.BPOperStatus != infradb.BridgePortOperStatusToBeDeleted { - status := setUpBp(BP) + details, status := setUpBp(BP) comp.Name = lciComp + comp.Details = details if status { - comp.Details = "" comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 } else { @@ -102,8 +105,9 @@ func handlebp(objectData *eventbus.ObjectData) { log.Printf("error in updating bp status: %s\n", err) } } else { - status := tearDownBp(BP) + details, status := tearDownBp(BP) comp.Name = lciComp + comp.Details = details if status { comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 @@ -124,31 +128,31 @@ func handlebp(objectData *eventbus.ObjectData) { } // setUpBp sets up the bridge port -func setUpBp(bp *infradb.BridgePort) bool { +func setUpBp(bp *infradb.BridgePort) (string, bool) { resourceID := path.Base(bp.Name) bridge, err := nlink.LinkByName(ctx, "br-tenant") if err != nil { log.Printf("LCI: Unable to find key br-tenant\n") - return false + return fmt.Sprintf("LCI: Unable to find key br-tenant, %s", err), false } iface, err := nlink.LinkByName(ctx, resourceID) if err != nil { log.Printf("LCI: Unable to find key %s\n", resourceID) - return false + return fmt.Sprintf("LCI: Unable to find key %s\n", resourceID), false } if err := nlink.LinkSetMaster(ctx, iface, bridge); err != nil { log.Printf("LCI: Failed to add iface to bridge: %v", err) - return false + return fmt.Sprintf("LCI: Failed to add iface to bridge: %v", err), false } for _, bridgeRefName := range bp.Spec.LogicalBridges { BrObj, err := infradb.GetLB(bridgeRefName) if err != nil { log.Printf("LCI: unable to find key %s and error is %v", bridgeRefName, err) - return false + return fmt.Sprintf("LCI: unable to find key %s and error is %v", bridgeRefName, err), false } if BrObj.Spec.VlanID > math.MaxUint16 { log.Printf("LVM : VlanID %v value passed in Logical Bridge create is greater than 16 bit value\n", BrObj.Spec.VlanID) - return false + return fmt.Sprintf("LVM : VlanID %v value passed in Logical Bridge create is greater than 16 bit value\n", BrObj.Spec.VlanID), false } //TODO: Update opi-api to change vlanid to int16 in LogiclaBridge "https://linter.aip.dev/141/forbidden-types" vid := uint16(BrObj.Spec.VlanID) @@ -156,60 +160,60 @@ func setUpBp(bp *infradb.BridgePort) bool { case infradb.Access: if err := nlink.BridgeVlanAdd(ctx, iface, vid, true, true, false, false); err != nil { log.Printf("Failed to add vlan to bridge: %v", err) - return false + return fmt.Sprintf("Failed to add vlan to bridge: %v", err), false } case infradb.Trunk: // Example: bridge vlan add dev eth2 vid 20 if err := nlink.BridgeVlanAdd(ctx, iface, vid, false, false, false, false); err != nil { log.Printf("Failed to add vlan to bridge: %v", err) - return false + return fmt.Sprintf("Failed to add vlan to bridge: %v", err), false } default: log.Printf("Only ACCESS or TRUNK supported and not (%d)", bp.Spec.Ptype) - return false + return fmt.Sprintf("Only ACCESS or TRUNK supported and not (%d)", bp.Spec.Ptype), false } } if err := nlink.LinkSetUp(ctx, iface); err != nil { log.Printf("Failed to up iface link: %v", err) - return false + return fmt.Sprintf("Failed to up iface link: %v", err), false } - return true + return "", true } // tearDownBp tears down a bridge port -func tearDownBp(bp *infradb.BridgePort) bool { +func tearDownBp(bp *infradb.BridgePort) (string, bool) { resourceID := path.Base(bp.Name) iface, err := nlink.LinkByName(ctx, resourceID) if err != nil { log.Printf("LCI: Unable to find key %s\n", resourceID) - return false + return fmt.Sprintf("LCI: Unable to find key %s\n", resourceID), false } if err := nlink.LinkSetDown(ctx, iface); err != nil { log.Printf("LCI: Failed to down link: %v", err) - return false + return fmt.Sprintf("LCI: Failed to down link: %v", err), false } for _, bridgeRefName := range bp.Spec.LogicalBridges { BrObj, err := infradb.GetLB(bridgeRefName) if err != nil { log.Printf("LCI: unable to find key %s and error is %v", bridgeRefName, err) - return false + return fmt.Sprintf("LCI: unable to find key %s and error is %v", bridgeRefName, err), false } if BrObj.Spec.VlanID > math.MaxUint16 { log.Printf("LVM : VlanID %v value passed in Logical Bridge create is greater than 16 bit value\n", BrObj.Spec.VlanID) - return false + return fmt.Sprintf("LVM : VlanID %v value passed in Logical Bridge create is greater than 16 bit value\n", BrObj.Spec.VlanID), false } //TODO: Update opi-api to change vlanid to uint16 in LogiclaBridge vid := uint16(BrObj.Spec.VlanID) if err := nlink.BridgeVlanDel(ctx, iface, vid, true, true, false, false); err != nil { log.Printf("LCI: Failed to delete vlan to bridge: %v", err) - return false + return fmt.Sprintf("LCI: Failed to delete vlan to bridge: %v", err), false } } if err := nlink.LinkDel(ctx, iface); err != nil { log.Printf("Failed to delete link: %v", err) - return false + return fmt.Sprintf("Failed to delete link: %v", err), false } - return true + return "", true } var ctx context.Context diff --git a/pkg/LinuxGeneralModule/lgm.go b/pkg/LinuxGeneralModule/lgm.go index 5140bd05..d8fd61b0 100644 --- a/pkg/LinuxGeneralModule/lgm.go +++ b/pkg/LinuxGeneralModule/lgm.go @@ -94,6 +94,7 @@ func handleLB(objectData *eventbus.ObjectData) { log.Printf("LGM: GetLB error: %s %s\n", err, objectData.Name) comp.Name = lgmComp comp.CompStatus = common.ComponentStatusError + comp.Details = fmt.Sprintf("LGM: GetLB error: %s %s\n", err, objectData.Name) if comp.Timer == 0 { comp.Timer = 2 * time.Second } else { @@ -109,6 +110,7 @@ func handleLB(objectData *eventbus.ObjectData) { log.Printf("LGM: Mismatch in resoruce version %+v\n and lb resource version %+v\n", objectData.ResourceVersion, lb.ResourceVersion) comp.Name = lgmComp comp.CompStatus = common.ComponentStatusError + comp.Details = fmt.Sprintf("LGM: Mismatch in resoruce version %+v\n and lb resource version %+v\n", objectData.ResourceVersion, lb.ResourceVersion) if comp.Timer == 0 { comp.Timer = 2 * time.Second } else { @@ -128,10 +130,10 @@ func handleLB(objectData *eventbus.ObjectData) { } } if lb.Status.LBOperStatus != infradb.LogicalBridgeOperStatusToBeDeleted { - status := setUpBridge(lb) + details, status := setUpBridge(lb) comp.Name = lgmComp + comp.Details = details if status { - comp.Details = "" comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 } else { @@ -148,8 +150,9 @@ func handleLB(objectData *eventbus.ObjectData) { log.Printf("error in updating lb status: %s\n", err) } } else { - status := tearDownBridge(lb) + details, status := tearDownBridge(lb) comp.Name = lgmComp + comp.Details = details if status { comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 @@ -194,6 +197,7 @@ func handlesvi(objectData *eventbus.ObjectData) { log.Printf("LGM: Mismatch in resoruce version %+v\n and svi resource version %+v\n", objectData.ResourceVersion, svi.ResourceVersion) comp.Name = lgmComp comp.CompStatus = common.ComponentStatusError + comp.Details = fmt.Sprintf("LGM: Mismatch in resoruce version %+v\n and svi resource version %+v\n", objectData.ResourceVersion, svi.ResourceVersion) if comp.Timer == 0 { comp.Timer = 2 * time.Second } else { @@ -213,8 +217,9 @@ func handlesvi(objectData *eventbus.ObjectData) { } } if svi.Status.SviOperStatus != infradb.SviOperStatusToBeDeleted { - status := setUpSvi(svi) + details, status := setUpSvi(svi) comp.Name = lgmComp + comp.Details = details if status { comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 @@ -232,8 +237,9 @@ func handlesvi(objectData *eventbus.ObjectData) { log.Printf("error in updating svi status: %s\n", err) } } else { - status := tearDownSvi(svi) + details, status := tearDownSvi(svi) comp.Name = lgmComp + comp.Details = details if status { comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 @@ -263,6 +269,7 @@ func handlevrf(objectData *eventbus.ObjectData) { log.Printf("LGM: GetVRF error: %s %s\n", err, objectData.Name) comp.Name = lgmComp comp.CompStatus = common.ComponentStatusError + comp.Details = fmt.Sprintf("LGM: GetVRF error: %s %s\n", err, objectData.Name) if comp.Timer == 0 { // wait timer is 2 powerof natural numbers ex : 1,2,3... comp.Timer = 2 * time.Second } else { @@ -278,6 +285,7 @@ func handlevrf(objectData *eventbus.ObjectData) { log.Printf("LGM: Mismatch in resoruce version %+v\n and vrf resource version %+v\n", objectData.ResourceVersion, vrf.ResourceVersion) comp.Name = lgmComp comp.CompStatus = common.ComponentStatusError + comp.Details = fmt.Sprintf("LGM: Mismatch in resoruce version %+v\n and vrf resource version %+v\n", objectData.ResourceVersion, vrf.ResourceVersion) if comp.Timer == 0 { // wait timer is 2 powerof natural numbers ex : 1,2,3... comp.Timer = 2 * time.Second } else { @@ -299,8 +307,8 @@ func handlevrf(objectData *eventbus.ObjectData) { if vrf.Status.VrfOperStatus != infradb.VrfOperStatusToBeDeleted { details, status := setUpVrf(vrf) comp.Name = lgmComp + comp.Details = details if status { - comp.Details = details comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 } else { @@ -317,8 +325,9 @@ func handlevrf(objectData *eventbus.ObjectData) { log.Printf("error in updating vrf status: %s\n", err) } } else { - status := tearDownVrf(vrf) + details, status := tearDownVrf(vrf) comp.Name = lgmComp + comp.Details = details if status { comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 @@ -411,42 +420,42 @@ func routingTableBusy(table uint32) (bool, error) { } // setUpBridge sets up the bridge -func setUpBridge(lb *infradb.LogicalBridge) bool { +func setUpBridge(lb *infradb.LogicalBridge) (string, bool) { link := fmt.Sprintf("vxlan-%+v", lb.Spec.VlanID) if !reflect.ValueOf(lb.Spec.Vni).IsZero() { brIntf, err := nlink.LinkByName(ctx, brTenant) if err != nil { log.Printf("LGM: Failed to get link information for %s: %v\n", brTenant, err) - return false + return fmt.Sprintf("LGM: Failed to get link information for %s: %v\n", brTenant, err), false } vxlan := &netlink.Vxlan{LinkAttrs: netlink.LinkAttrs{Name: link, MTU: ipMtu}, VxlanId: int(*lb.Spec.Vni), Port: 4789, Learning: false, SrcAddr: lb.Spec.VtepIP.IP} if err := nlink.LinkAdd(ctx, vxlan); err != nil { log.Printf("LGM: Failed to create Vxlan linki %s: %v\n", link, err) - return false + return fmt.Sprintf("LGM: Failed to create Vxlan linki %s: %v\n", link, err), false } // Example: ip link set vxlan- master br-tenant addrgenmode none if err = nlink.LinkSetMaster(ctx, vxlan, brIntf); err != nil { log.Printf("LGM: Failed to add Vxlan %s to bridge %s: %v\n", link, brTenant, err) - return false + return fmt.Sprintf("LGM: Failed to add Vxlan %s to bridge %s: %v\n", link, brTenant, err), false } // Example: ip link set vxlan- up if err = nlink.LinkSetUp(ctx, vxlan); err != nil { log.Printf("LGM: Failed to up Vxlan link %s: %v\n", link, err) - return false + return fmt.Sprintf("LGM: Failed to up Vxlan link %s: %v\n", link, err), false } // Example: bridge vlan add dev vxlan- vid pvid untagged if err = nlink.BridgeVlanAdd(ctx, vxlan, uint16(lb.Spec.VlanID), true, true, false, false); err != nil { log.Printf("LGM: Failed to add vlan to bridge %s: %v\n", brTenant, err) - return false + return fmt.Sprintf("LGM: Failed to add vlan to bridge %s: %v\n", brTenant, err), false } if err = nlink.LinkSetBrNeighSuppress(ctx, vxlan, true); err != nil { log.Printf("LGM: Failed to add bridge %v neigh_suppress: %s\n", vxlan, err) - return false + return fmt.Sprintf("LGM: Failed to add bridge %v neigh_suppress: %s\n", vxlan, err), false } - return true + return "", true } - return true + return "", true } // setUpVrf sets up the vrf @@ -470,7 +479,7 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { isBusy, err := routingTableBusy(routingTable) if err != nil { log.Printf("LGM : Error occurred when checking if routing table %d is busy: %+v\n", routingTable, err) - return "", false + return fmt.Sprintf("LGM : Error occurred when checking if routing table %d is busy: %+v\n", routingTable, err), false } if !isBusy { log.Printf("LGM: Routing Table %d is not busy\n", routingTable) @@ -486,7 +495,7 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { // Not found similar API in viswananda library so retain the linux commands as it is .. not able to get the route list exact vtip table local if !err { log.Printf(" LGM: VTEP IP not found: %+v\n", vrf.Spec.VtepIP) - return "", false + return fmt.Sprintf(" LGM: VTEP IP not found: %+v\n", vrf.Spec.VtepIP), false } } log.Printf("setUpVrf: %s %d\n", vtip, routingTable) @@ -498,7 +507,7 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { }) if linkAdderr != nil { log.Printf("LGM: Error in Adding vrf link table %d\n", routingTable) - return "", false + return fmt.Sprintf("LGM: Error in Adding vrf link table %d\n", routingTable), false } log.Printf("LGM: vrf link %s Added with table id %d\n", vrf.Name, routingTable) @@ -506,19 +515,19 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { link, linkErr := nlink.LinkByName(ctx, path.Base(vrf.Name)) if linkErr != nil { log.Printf("LGM : Link %s not found\n", vrf.Name) - return "", false + return fmt.Sprintf("LGM : Link %s not found\n", vrf.Name), false } linkmtuErr := nlink.LinkSetMTU(ctx, link, ipMtu) if linkmtuErr != nil { log.Printf("LGM : Unable to set MTU to link %s \n", vrf.Name) - return "", false + return fmt.Sprintf("LGM : Unable to set MTU to link %s \n", vrf.Name), false } linksetupErr := nlink.LinkSetUp(ctx, link) if linksetupErr != nil { log.Printf("LGM : Unable to set link %s UP \n", vrf.Name) - return "", false + return fmt.Sprintf("LGM : Unable to set link %s UP \n", vrf.Name), false } Lbip := fmt.Sprintf("%+v", vrf.Spec.LoopbackIP.IP) @@ -529,7 +538,7 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { addrErr := nlink.AddrAdd(ctx, link, Addrs) if addrErr != nil { log.Printf("LGM: Unable to set the loopback ip to vrf link %s \n", vrf.Name) - return "", false + return fmt.Sprintf("LGM: Unable to set the loopback ip to vrf link %s \n", vrf.Name), false } log.Printf("LGM: Added Address %s dev %s\n", Lbip, vrf.Name) @@ -545,7 +554,7 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { routeaddErr := nlink.RouteAdd(ctx, &route) if routeaddErr != nil { log.Printf("LGM : Failed in adding Route throw default %+v\n", routeaddErr) - return "", false + return fmt.Sprintf("LGM : Failed in adding Route throw default %+v\n", routeaddErr), false } log.Printf("LGM : Added route throw default table %d proto opi_evpn_br metric 9999\n", routingTable) @@ -563,7 +572,7 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { }) if brErr != nil { log.Printf("LGM : Error in added bridge port\n") - return "", false + return fmt.Sprintf("LGM : Error in added bridge port %v", brErr), false } log.Printf("LGM : Added link br-%s type bridge\n", vrf.Name) @@ -573,36 +582,36 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { linkBr, brErr := nlink.LinkByName(ctx, brStr+path.Base(vrf.Name)) if brErr != nil { log.Printf("LGM : Error in getting the br-%s\n", vrf.Name) - return "", false + return fmt.Sprintf("LGM : Error in getting the br-%s\n", vrf.Name), false } hwErr := nlink.LinkSetHardwareAddr(ctx, linkBr, hw) if hwErr != nil { log.Printf("LGM: Failed in the setting Hardware Address\n") - return "", false + return fmt.Sprintf("LGM: Failed in the setting Hardware Address: %v\n", hwErr), false } linkmtuErr := nlink.LinkSetMTU(ctx, linkBr, ipMtu) if linkmtuErr != nil { log.Printf("LGM : Unable to set MTU to link br-%s \n", vrf.Name) - return "", false + return fmt.Sprintf("LGM : Unable to set MTU to link br-%s \n", vrf.Name), false } linkMaster, errMaster := nlink.LinkByName(ctx, path.Base(vrf.Name)) if errMaster != nil { log.Printf("LGM : Error in getting the %s\n", vrf.Name) - return "", false + return fmt.Sprintf("LGM : Error in getting the %s\n", vrf.Name), false } err := nlink.LinkSetMaster(ctx, linkBr, linkMaster) if err != nil { log.Printf("LGM : Unable to set the master to br-%s link", vrf.Name) - return "", false + return fmt.Sprintf("LGM : Unable to set the master to br-%s link", vrf.Name), false } linksetupErr = nlink.LinkSetUp(ctx, linkBr) if linksetupErr != nil { log.Printf("LGM : Unable to set link %s UP \n", vrf.Name) - return "", false + return fmt.Sprintf("LGM : Unable to set link %s UP \n", vrf.Name), false } log.Printf("LGM: link set br-%s master %s up mtu \n", vrf.Name, IPMtu) @@ -613,7 +622,7 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { LinkAttrs: netlink.LinkAttrs{Name: vxlanStr + path.Base(vrf.Name), MTU: ipMtu}, VxlanId: int(*vrf.Spec.Vni), SrcAddr: SrcVtep, Learning: false, Proxy: true, Port: 4789}) if vxlanErr != nil { log.Printf("LGM : Error in added vxlan port\n") - return "", false + return fmt.Sprintf("LGM : Error in added vxlan port %v\n", vxlanErr), false } log.Printf("LGM : link added vxlan-%s type vxlan id %d local %s dstport 4789 nolearning proxy\n", vrf.Name, *vrf.Spec.Vni, vtip) @@ -621,13 +630,13 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { linkVxlan, vxlanErr := nlink.LinkByName(ctx, vxlanStr+path.Base(vrf.Name)) if vxlanErr != nil { log.Printf("LGM : Error in getting the %s\n", vxlanStr+vrf.Name) - return "", false + return fmt.Sprintf("LGM : Error in getting the %s\n", vxlanStr+vrf.Name), false } err = nlink.LinkSetMaster(ctx, linkVxlan, linkBr) if err != nil { log.Printf("LGM : Unable to set the master to vxlan-%s link", vrf.Name) - return "", false + return fmt.Sprintf("LGM : Unable to set the master to vxlan-%s link", vrf.Name), false } log.Printf("LGM: vrf Link vxlan setup master\n") @@ -635,7 +644,7 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { linksetupErr = nlink.LinkSetUp(ctx, linkVxlan) if linksetupErr != nil { log.Printf("LGM : Unable to set link %s UP \n", vrf.Name) - return "", false + return fmt.Sprintf("LGM : Unable to set link %s UP \n", vrf.Name), false } } details := fmt.Sprintf("{\"routingTable\":\"%d\"}", routingTable) @@ -644,58 +653,58 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { } // setUpSvi sets up the svi -func setUpSvi(svi *infradb.Svi) bool { +func setUpSvi(svi *infradb.Svi) (string, bool) { BrObj, err := infradb.GetLB(svi.Spec.LogicalBridge) if err != nil { log.Printf("LGM: unable to find key %s and error is %v", svi.Spec.LogicalBridge, err) - return false + return fmt.Sprintf("LGM: unable to find key %s and error is %v", svi.Spec.LogicalBridge, err), false } linkSvi := fmt.Sprintf("%+v-%+v", path.Base(svi.Spec.Vrf), BrObj.Spec.VlanID) brIntf, err := nlink.LinkByName(ctx, brTenant) if err != nil { log.Printf("LGM : Failed to get link information for %s: %v\n", brTenant, err) - return false + return fmt.Sprintf("LGM : Failed to get link information for %s: %v\n", brTenant, err), false } if BrObj.Spec.VlanID > math.MaxUint16 { log.Printf("LGM : VlanID %v value passed in Logical Bridge create is greater than 16 bit value\n", BrObj.Spec.VlanID) - return false + return fmt.Sprintf("LGM : VlanID %v value passed in Logical Bridge create is greater than 16 bit value\n", BrObj.Spec.VlanID), false } vid := uint16(BrObj.Spec.VlanID) if err = nlink.BridgeVlanAdd(ctx, brIntf, vid, false, false, true, false); err != nil { log.Printf("LGM : Failed to add VLAN %d to bridge interface %s: %v\n", vid, brTenant, err) - return false + return fmt.Sprintf("LGM : Failed to add VLAN %d to bridge interface %s: %v\n", vid, brTenant, err), false } log.Printf("LGM Executed : bridge vlan add dev %s vid %d self\n", brTenant, vid) vlanLink := &netlink.Vlan{LinkAttrs: netlink.LinkAttrs{Name: linkSvi, ParentIndex: brIntf.Attrs().Index}, VlanId: int(BrObj.Spec.VlanID)} if err = nlink.LinkAdd(ctx, vlanLink); err != nil { log.Printf("LGM : Failed to add VLAN sub-interface %s: %v\n", linkSvi, err) - return false + return fmt.Sprintf("LGM : Failed to add VLAN sub-interface %s: %v\n", linkSvi, err), false } log.Printf("LGM Executed : ip link add link %s name %s type vlan id %d\n", brTenant, linkSvi, vid) if err = nlink.LinkSetHardwareAddr(ctx, vlanLink, *svi.Spec.MacAddress); err != nil { log.Printf("LGM : Failed to set link %v: %s\n", vlanLink, err) - return false + return fmt.Sprintf("LGM : Failed to set link %v: %s\n", vlanLink, err), false } log.Printf("LGM Executed : ip link set %s address %s\n", linkSvi, *svi.Spec.MacAddress) vrfIntf, err := nlink.LinkByName(ctx, path.Base(svi.Spec.Vrf)) if err != nil { log.Printf("LGM : Failed to get link information for %s: %v\n", path.Base(svi.Spec.Vrf), err) - return false + return fmt.Sprintf("LGM : Failed to get link information for %s: %v\n", path.Base(svi.Spec.Vrf), err), false } if err = nlink.LinkSetMaster(ctx, vlanLink, vrfIntf); err != nil { log.Printf("LGM : Failed to set master for %v: %s\n", vlanLink, err) - return false + return fmt.Sprintf("LGM : Failed to set master for %v: %s\n", vlanLink, err), false } if err = nlink.LinkSetUp(ctx, vlanLink); err != nil { log.Printf("LGM : Failed to set up link for %v: %s\n", vlanLink, err) - return false + return fmt.Sprintf("LGM : Failed to set up link for %v: %s\n", vlanLink, err), false } if err = nlink.LinkSetMTU(ctx, vlanLink, ipMtu); err != nil { log.Printf("LGM : Failed to set MTU for %v: %s\n", vlanLink, err) - return false + return fmt.Sprintf("LGM : Failed to set MTU for %v: %s\n", vlanLink, err), false } log.Printf("LGM Executed : ip link set %s master %s up mtu %d\n", linkSvi, path.Base(svi.Spec.Vrf), ipMtu) @@ -716,12 +725,12 @@ func setUpSvi(svi *infradb.Svi) bool { } if err := nlink.AddrAdd(ctx, vlanLink, addr); err != nil { log.Printf("LGM: Failed to add ip address %v to %v: %v\n", addr, vlanLink, err) - return false + return fmt.Sprintf("LGM: Failed to add ip address %v to %v: %v\n", addr, vlanLink, err), false } log.Printf("LGM Executed : ip address add %s dev %+v\n", addr, vlanLink) } - return true + return "", true } // GenerateMac Generates the random mac @@ -765,15 +774,15 @@ func NetMaskToInt(mask int) (netmaskint [4]int64) { } // tearDownVrf tears down the vrf -func tearDownVrf(vrf *infradb.Vrf) bool { +func tearDownVrf(vrf *infradb.Vrf) (string, bool) { link, err1 := nlink.LinkByName(ctx, path.Base(vrf.Name)) if err1 != nil { log.Printf("LGM : Link %s not found %+v\n", vrf.Name, err1) - return true + return fmt.Sprintf("LGM : Link %s not found %+v\n", vrf.Name, err1), true } if path.Base(vrf.Name) == "GRD" { - return true + return "", true } routingTable := *vrf.Metadata.RoutingTable[0] // Delete the Linux networking artefacts in reverse order @@ -781,24 +790,24 @@ func tearDownVrf(vrf *infradb.Vrf) bool { linkVxlan, linkErr := nlink.LinkByName(ctx, vxlanStr+path.Base(vrf.Name)) if linkErr != nil { log.Printf("LGM : Link vxlan-%s not found %+v\n", vrf.Name, linkErr) - return false + return fmt.Sprintf("LGM : Link vxlan-%s not found %+v\n", vrf.Name, linkErr), false } delerr := nlink.LinkDel(ctx, linkVxlan) if delerr != nil { log.Printf("LGM: Error in delete vxlan %+v\n", delerr) - return false + return fmt.Sprintf("LGM: Error in delete vxlan %+v\n", delerr), false } log.Printf("LGM : Delete vxlan-%s\n", vrf.Name) linkBr, linkbrErr := nlink.LinkByName(ctx, brStr+path.Base(vrf.Name)) if linkbrErr != nil { log.Printf("LGM : Link br-%s not found %+v\n", vrf.Name, linkbrErr) - return false + return fmt.Sprintf("LGM : Link br-%s not found %+v\n", vrf.Name, linkbrErr), false } delerr = nlink.LinkDel(ctx, linkBr) if delerr != nil { log.Printf("LGM: Error in delete br %+v\n", delerr) - return false + return fmt.Sprintf("LGM: Error in delete br %+v\n", delerr), false } log.Printf("LGM : Delete br-%s\n", vrf.Name) } @@ -806,74 +815,74 @@ func tearDownVrf(vrf *infradb.Vrf) bool { flusherr := nlink.RouteFlushTable(ctx, routeTable) if flusherr != nil { log.Printf("LGM: Error in flush table %+v\n", routeTable) - return false + return fmt.Sprintf("LGM: Error in flush table %+v\n", routeTable), false } log.Printf("LGM Executed : ip route flush table %s\n", routeTable) delerr := nlink.LinkDel(ctx, link) if delerr != nil { log.Printf("LGM: Error in delete br %+v\n", delerr) - return false + return fmt.Sprintf("LGM: Error in delete br %+v\n", delerr), false } log.Printf("LGM :link delete %s\n", vrf.Name) - return true + return "", true } // tearDownSvi tears down the svi -func tearDownSvi(svi *infradb.Svi) bool { +func tearDownSvi(svi *infradb.Svi) (string, bool) { BrObj, err := infradb.GetLB(svi.Spec.LogicalBridge) if err != nil { log.Printf("LGM: unable to find key %s and error is %v", svi.Spec.LogicalBridge, err) - return false + return fmt.Sprintf("LGM: unable to find key %s and error is %v", svi.Spec.LogicalBridge, err), false } brIntf, err := nlink.LinkByName(ctx, brTenant) if err != nil { log.Printf("LGM : Failed to get link information for %s: %v\n", brTenant, err) - return false + return fmt.Sprintf("LGM : Failed to get link information for %s: %v\n", brTenant, err), false } if BrObj.Spec.VlanID > math.MaxUint16 { log.Printf("LGM : VlanID %v value passed in Logical Bridge create is greater than 16 bit value\n", BrObj.Spec.VlanID) - return false + return fmt.Sprintf("LGM : VlanID %v value passed in Logical Bridge create is greater than 16 bit value\n", BrObj.Spec.VlanID), false } vid := uint16(BrObj.Spec.VlanID) if err = nlink.BridgeVlanDel(ctx, brIntf, vid, false, false, true, false); err != nil { log.Printf("LGM : Failed to Del VLAN %d to bridge interface %s: %v\n", vid, brTenant, err) - return false + return fmt.Sprintf("LGM : Failed to Del VLAN %d to bridge interface %s: %v\n", vid, brTenant, err), false } log.Printf("LGM Executed : bridge vlan del dev %s vid %d self\n", brTenant, vid) linkSvi := fmt.Sprintf("%+v-%+v", path.Base(svi.Spec.Vrf), BrObj.Spec.VlanID) Intf, err := nlink.LinkByName(ctx, linkSvi) if err != nil { log.Printf("LGM : Failed to get link %s: %v\n", linkSvi, err) - return true + return fmt.Sprintf("LGM : Failed to get link %s: %v\n", linkSvi, err), true } if err = nlink.LinkDel(ctx, Intf); err != nil { log.Printf("LGM : Failed to delete link %s: %v\n", linkSvi, err) - return false + return fmt.Sprintf("LGM : Failed to delete link %s: %v\n", linkSvi, err), false } log.Printf("LGM: Executed ip link delete %s\n", linkSvi) - return true + return "", true } // tearDownBridge tears down the bridge -func tearDownBridge(lb *infradb.LogicalBridge) bool { +func tearDownBridge(lb *infradb.LogicalBridge) (string, bool) { link := fmt.Sprintf("vxlan-%+v", lb.Spec.VlanID) if !reflect.ValueOf(lb.Spec.Vni).IsZero() { Intf, err := nlink.LinkByName(ctx, link) if err != nil { log.Printf("LGM: Failed to get link %s: %v\n", link, err) - return true + return fmt.Sprintf("LGM: Failed to get link %s: %v\n", link, err), true } if err = nlink.LinkDel(ctx, Intf); err != nil { log.Printf("LGM : Failed to delete link %s: %v\n", link, err) - return false + return fmt.Sprintf("LGM: Failed to delete link %s: %v\n", link, err), false } log.Printf("LGM: Executed ip link delete %s", link) - return true + return "", true } - return true + return "", true } // TearDownTenantBridge tears down the bridge diff --git a/pkg/frr/frr.go b/pkg/frr/frr.go index 5deeec02..afca3401 100644 --- a/pkg/frr/frr.go +++ b/pkg/frr/frr.go @@ -11,12 +11,11 @@ import ( "fmt" "log" - "net" "os" "os/exec" "os/user" "path" - "reflect" + "regexp" "strconv" "strings" "time" @@ -35,8 +34,39 @@ const frrComp string = "frr" // replayThreshold time threshold for replay const replayThreshold = 64 * time.Second -// ModulefrrHandler empty structure -type ModulefrrHandler struct{} +// moduleFrrHandler empty structure +type moduleFrrHandler struct{} + +// bgpl2VpnCmd structure +type bgpl2VpnCmd struct { + Vni int + Type string + InKernel string + Rd string + OriginatorIP string + AdvertiseGatewayMacip string + AdvertiseSviMacIP string + AdvertisePip string + SysIP string + SysMac string + Rmac string + ImportRts []string + ExportRts []string +} + +// route empty structure +type route struct{} + +// bgpVrfCmd structure +type bgpVrfCmd struct { + VrfID int + VrfName string + TableVersion uint + RouterID string + DefaultLocPrf uint + LocalAS int + Routes route +} // ModuleFrrActionHandler empty structure type ModuleFrrActionHandler struct { @@ -67,7 +97,7 @@ func NewModuleFrrActionHandlerWithArgs(runningFrrConfFile, basicFrrConfFile, bac } // HandleEvent handles the events -func (h *ModulefrrHandler) HandleEvent(eventType string, objectData *eventbus.ObjectData) { +func (h *moduleFrrHandler) HandleEvent(eventType string, objectData *eventbus.ObjectData) { switch eventType { case "vrf": // "VRF_added": log.Printf("FRR recevied %s %s\n", eventType, objectData.Name) @@ -166,6 +196,7 @@ func handlesvi(objectData *eventbus.ObjectData) { log.Printf("GetSvi error: %s %s\n", err, objectData.Name) comp.Name = frrComp comp.CompStatus = common.ComponentStatusError + comp.Details = fmt.Sprintf("GetSvi error: %s %s\n", err, objectData.Name) if comp.Timer == 0 { comp.Timer = 2 * time.Second } else { @@ -182,6 +213,7 @@ func handlesvi(objectData *eventbus.ObjectData) { log.Printf("FRR: Mismatch in resoruce version %+v\n and svi resource version %+v\n", objectData.ResourceVersion, svi.ResourceVersion) comp.Name = frrComp comp.CompStatus = common.ComponentStatusError + comp.Details = fmt.Sprintf("FRR: Mismatch in resoruce version %+v\n and svi resource version %+v\n", objectData.ResourceVersion, svi.ResourceVersion) if comp.Timer == 0 { comp.Timer = 2 * time.Second } else { @@ -201,8 +233,9 @@ func handlesvi(objectData *eventbus.ObjectData) { } } if svi.Status.SviOperStatus != infradb.SviOperStatusToBeDeleted { - status := setUpSvi(svi) + details, status := setUpSvi(svi) comp.Name = frrComp + comp.Details = details if status { comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 @@ -224,8 +257,9 @@ func handlesvi(objectData *eventbus.ObjectData) { log.Printf("error in updating svi status: %s\n", err) } } else { - status := tearDownSvi(svi) + details, status := tearDownSvi(svi) comp.Name = frrComp + comp.Details = details if status { comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 @@ -259,6 +293,7 @@ func handlevrf(objectData *eventbus.ObjectData) { log.Printf("GetVRF error: %s %s\n", err, objectData.Name) comp.Name = frrComp comp.CompStatus = common.ComponentStatusError + comp.Details = fmt.Sprintf("GetVRF error: %s %s\n", err, objectData.Name) if comp.Timer == 0 { // wait timer is 2 powerof natural numbers ex : 1,2,3... comp.Timer = 2 * time.Second } else { @@ -271,17 +306,11 @@ func handlevrf(objectData *eventbus.ObjectData) { return } - if len(vrf.Status.Components) != 0 { - for i := 0; i < len(vrf.Status.Components); i++ { - if vrf.Status.Components[i].Name == frrComp { - comp = vrf.Status.Components[i] - } - } - } if objectData.ResourceVersion != vrf.ResourceVersion { log.Printf("FRR: Mismatch in resoruce version %+v\n and vrf resource version %+v\n", objectData.ResourceVersion, vrf.ResourceVersion) comp.Name = frrComp comp.CompStatus = common.ComponentStatusError + comp.Details = fmt.Sprintf("FRR: Mismatch in resoruce version %+v\n and vrf resource version %+v\n", objectData.ResourceVersion, vrf.ResourceVersion) if comp.Timer == 0 { // wait timer is 2 powerof natural numbers ex : 1,2,3... comp.Timer = 2 * time.Second } else { @@ -303,8 +332,8 @@ func handlevrf(objectData *eventbus.ObjectData) { if vrf.Status.VrfOperStatus != infradb.VrfOperStatusToBeDeleted { detail, status := setUpVrf(vrf) comp.Name = frrComp + comp.Details = detail if status { - comp.Details = detail comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 } else { @@ -325,8 +354,9 @@ func handlevrf(objectData *eventbus.ObjectData) { log.Printf("error in updating vrf status: %s\n", err) } } else { - status := tearDownVrf(vrf) + details, status := tearDownVrf(vrf) comp.Name = frrComp + comp.Details = details if status { comp.CompStatus = common.ComponentStatusSuccess comp.Timer = 0 @@ -381,7 +411,7 @@ func subscribeInfradb(config *config.Config) { for _, subscriberConfig := range config.Subscribers { if subscriberConfig.Name == frrComp { for _, eventType := range subscriberConfig.Events { - eb.StartSubscriber(subscriberConfig.Name, eventType, subscriberConfig.Priority, &ModulefrrHandler{}) + eb.StartSubscriber(subscriberConfig.Name, eventType, subscriberConfig.Priority, &moduleFrrHandler{}) } } } @@ -391,8 +421,8 @@ func subscribeInfradb(config *config.Config) { // ctx variable of type context var ctx context.Context -// Frr variable of type utils wrapper -var Frr utils.Frr +// frr variable of type utils wrapper +var frr utils.Frr // Initialize function handles init functionality func Initialize() { @@ -410,7 +440,7 @@ func Initialize() { subscribeInfradb(&config.GlobalConfig) ctx = context.Background() - Frr = utils.NewFrrWrapperWithArgs("localhost", config.GlobalConfig.Tracer) + frr = utils.NewFrrWrapperWithArgs("localhost", config.GlobalConfig.Tracer) // Make sure IPv4 forwarding is enabled. detail, flag := run([]string{"sysctl", "-w", " net.ipv4.ip_forward=1"}, false) @@ -431,139 +461,91 @@ func DeInitialize() { eb.UnsubscribeModule(frrComp) } -// routingTableBusy function checks the routing table -/*func routingTableBusy(table uint32) bool { - cp, err := run([]string{"ip", "route", "show", "table", strconv.Itoa(int(table))}, false) - if err != 0 { - fmt.Println(cp) - return false - } - // fmt.Printf("route table busy %s %s\n",cp,err) - // Table is busy if it exists and contains some routes - return true // reflect.ValueOf(cp).IsZero() && len(cp)!= 0 -}*/ - -// VRF structure -type VRF struct { - Name string - Vni int - RoutingTables []uint32 - Loopback net.IP - // RoutingTables uint32 -} - -// BgpL2vpnCmd structure -type BgpL2vpnCmd struct { - Vni int - Type string - InKernel string - Rd string - OriginatorIP string - AdvertiseGatewayMacip string - AdvertiseSviMacIP string - AdvertisePip string - SysIP string - SysMac string - Rmac string - ImportRts []string - ExportRts []string -} - -// route empty structure -type route struct{} - -// BgpVrfCmd structure -type BgpVrfCmd struct { - VrfID int - VrfName string - TableVersion uint - RouterID string - DefaultLocPrf uint - LocalAS int - Routes route -} - // setUpVrf sets up the vrf +// +//nolint:funlen,gocognit func setUpVrf(vrf *infradb.Vrf) (string, bool) { // This function must not be executed for the vrf representing the GRD if path.Base(vrf.Name) == "GRD" { return "", true } - if !reflect.ValueOf(vrf.Spec.Vni).IsZero() { + if *vrf.Spec.Vni != 0 { // Configure the vrf in FRR and set up BGP EVPN for it vrfName := fmt.Sprintf("vrf %s", path.Base(vrf.Name)) vniID := fmt.Sprintf("vni %s", strconv.Itoa(int(*vrf.Spec.Vni))) - _, err := Frr.FrrZebraCmd(ctx, fmt.Sprintf("configure terminal\n %s\n %s\n exit-vrf\n exit", vrfName, vniID)) - // fmt.Printf("FrrZebraCmd: %v:%v", data, err) + + _, err := frr.FrrZebraCmd(ctx, fmt.Sprintf("configure terminal\n %s\n %s\n exit-vrf\n exit", vrfName, vniID), false) if err != nil { - return "", false + log.Printf("FRR: Error Executing frr config t %s %s exit-vrf exit \n Error: is%v\n", vrfName, vniID, err) + return fmt.Sprintf("FRR: Error Executing frr config t %s %s exit-vrf exit \n Error: %v \n", vrfName, vniID, err), false } - err = Frr.Save(ctx) + err = frr.Save(ctx) if err != nil { log.Printf("FRR(setUpVrf): Failed to run save command: %v\n", err) } log.Printf("FRR: Executed frr config t %s %s exit-vrf exit\n", vrfName, vniID) - var LbiP string + var lbIP string - if reflect.ValueOf(vrf.Spec.LoopbackIP).IsZero() { - LbiP = "0.0.0.0" + if vrf.Spec.LoopbackIP != nil { + lbIP = "0.0.0.0" } else { - LbiP = fmt.Sprintf("%+v", vrf.Spec.LoopbackIP.IP) + lbIP = fmt.Sprintf("%+v", vrf.Spec.LoopbackIP.IP) } - _, err = Frr.FrrBgpCmd(ctx, fmt.Sprintf("configure terminal\n router bgp %+v vrf %s\n bgp router-id %s\n no bgp ebgp-requires-policy\n no bgp hard-administrative-reset\n no bgp graceful-restart notification\n address-family ipv4 unicast\n redistribute connected\n redistribute static\n exit-address-family\n address-family l2vpn evpn\n advertise ipv4 unicast\n exit-address-family\n exit", localas, path.Base(vrf.Name), LbiP)) + _, err = frr.FrrBgpCmd(ctx, fmt.Sprintf("configure terminal\n router bgp %+v vrf %s\n bgp router-id %s\n no bgp ebgp-requires-policy\n no bgp hard-administrative-reset\n no bgp graceful-restart notification\n address-family ipv4 unicast\n redistribute connected\n redistribute static\n exit-address-family\n address-family l2vpn evpn\n advertise ipv4 unicast\n exit-address-family\n exit", localas, path.Base(vrf.Name), lbIP), false) if err != nil { - return "", false + log.Printf("FRR: Error Executing config t bgpVrfName router bgp %+v vrf %s bgp_route_id %s no bgp ebgp-requires-policy exit-vrf exit Error %v \n", localas, vrf.Name, lbIP, err) + return fmt.Sprintf("FRR: Error Executing config t bgpVrfName router bgp %+v vrf %s bgp_route_id %s no bgp ebgp-requires-policy exit-vrf exit Error %v \n", localas, vrf.Name, lbIP, err), false } - err = Frr.Save(ctx) + err = frr.Save(ctx) if err != nil { log.Printf("FRR(setUpVrf): Failed to run save command: %v\n", err) } - log.Printf("FRR: Executed config t bgpVrfName router bgp %+v vrf %s bgp_route_id %s no bgp ebgp-requires-policy exit-vrf exit\n", localas, vrf.Name, LbiP) + log.Printf("FRR: Executed config t bgpVrfName router bgp %+v vrf %s bgp_route_id %s no bgp ebgp-requires-policy exit-vrf exit\n", localas, vrf.Name, lbIP) // Update the vrf with attributes from FRR cmd := fmt.Sprintf("show bgp l2vpn evpn vni %d json", *vrf.Spec.Vni) - cp, err := Frr.FrrBgpCmd(ctx, cmd) + cp, err := frr.FrrBgpCmd(ctx, cmd, true) if err != nil { - log.Printf("error-%v", err) + log.Printf("FRR Error-show bgp l2vpn evpn vni %v cp %v", err, cp) } - err = Frr.Save(ctx) + err = frr.Save(ctx) if err != nil { log.Printf("FRR(setUpVrf): Failed to run save command: %v\n", err) } hname, _ := os.Hostname() - L2vpnCmd := strings.Split(cp, "json") - L2vpnCmd = strings.Split(L2vpnCmd[1], hname) - cp = L2vpnCmd[0] - // fmt.Printf("FRR_L2vpn[0]: %s\n",cp) - if len(cp) != 7 { + l2VpnCmd := strings.Split(cp, "json") + l2VpnCmd = strings.Split(l2VpnCmd[1], hname) + cp = l2VpnCmd[0] + if regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString(cp) { cp = cp[3 : len(cp)-3] } else { log.Printf("FRR: unable to get the command %s\n", cmd) - return "", false + return fmt.Sprintf("FRR: unable to get the command %s\n", cmd), false } - var bgpL2vpn BgpL2vpnCmd + var bgpL2vpn bgpl2VpnCmd err1 := json.Unmarshal([]byte(fmt.Sprintf("{%v}", cp)), &bgpL2vpn) if err1 != nil { log.Printf("error-%v", err) } cmd = fmt.Sprintf("show bgp vrf %s json", path.Base(vrf.Name)) - cp, err = Frr.FrrBgpCmd(ctx, cmd) + cp, err = frr.FrrBgpCmd(ctx, cmd, true) if err != nil { log.Printf("error-%v", err) } - err = Frr.Save(ctx) + err = frr.Save(ctx) if err != nil { log.Printf("FRR(setUpVrf): Failed to run save command: %v\n", err) } - BgpCmd := strings.Split(cp, "json") - BgpCmd = strings.Split(BgpCmd[1], hname) - cp = BgpCmd[0] - var bgpVrf BgpVrfCmd + bgpCmd := strings.Split(cp, "json") + bgpCmd = strings.Split(bgpCmd[1], hname) + cp = bgpCmd[0] + + var bgpVrf bgpVrfCmd if len(cp) != 7 { cp = cp[5 : len(cp)-5] } else { log.Printf("FRR: unable to get the command \"%s\"\n", cmd) - return "", false + return fmt.Sprintf("FRR: unable to get the command \"%s\"\n", cmd), false } err1 = json.Unmarshal([]byte(fmt.Sprintf("{%v}", cp)), &bgpVrf) if err1 != nil { @@ -577,114 +559,110 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) { return "", true } -// checkFrrResult checks the vrf result -func checkFrrResult(cp string, show bool) bool { - return ((show && reflect.ValueOf(cp).IsZero()) || strings.Contains(cp, "warning") || strings.Contains(cp, "unknown") || strings.Contains(cp, "Unknown") || strings.Contains(cp, "Warning") || strings.Contains(cp, "Ambiguous") || strings.Contains(cp, "specified does not exist")) -} - // setUpSvi sets up the svi -func setUpSvi(svi *infradb.Svi) bool { - BrObj, err := infradb.GetLB(svi.Spec.LogicalBridge) +func setUpSvi(svi *infradb.Svi) (string, bool) { + brObj, err := infradb.GetLB(svi.Spec.LogicalBridge) if err != nil { log.Printf("FRR: unable to find key %s and error is %v", svi.Spec.LogicalBridge, err) - return false + return fmt.Sprintf("FRR: unable to find key %s and error is %v", svi.Spec.LogicalBridge, err), false } - linkSvi := fmt.Sprintf("%+v-%+v", path.Base(svi.Spec.Vrf), BrObj.Spec.VlanID) - if svi.Spec.EnableBgp && !reflect.ValueOf(svi.Spec.GatewayIPs).IsZero() { + linkSvi := fmt.Sprintf("%+v-%+v", path.Base(svi.Spec.Vrf), brObj.Spec.VlanID) + if svi.Spec.EnableBgp && len(svi.Spec.GatewayIPs) != 0 { // gwIP := fmt.Sprintf("%s", svi.Spec.GatewayIPs[0].IP.To4()) gwIP := string(svi.Spec.GatewayIPs[0].IP.To4()) - RemoteAs := fmt.Sprintf("%d", *svi.Spec.RemoteAs) + remoteAs := fmt.Sprintf("%d", *svi.Spec.RemoteAs) bgpVrfName := fmt.Sprintf("router bgp %+v vrf %s\n", localas, path.Base(svi.Spec.Vrf)) neighlink := fmt.Sprintf("neighbor %s peer-group\n", linkSvi) - neighlinkRe := fmt.Sprintf("neighbor %s remote-as %s\n", linkSvi, RemoteAs) + neighlinkRe := fmt.Sprintf("neighbor %s remote-as %s\n", linkSvi, remoteAs) neighlinkGw := fmt.Sprintf("neighbor %s update-source %s\n", linkSvi, gwIP) neighlinkOv := fmt.Sprintf("neighbor %s as-override\n", linkSvi) neighlinkSr := fmt.Sprintf("neighbor %s soft-reconfiguration inbound\n", linkSvi) bgpListen := fmt.Sprintf(" bgp listen range %s peer-group %s\n", svi.Spec.GatewayIPs[0], linkSvi) - data, err := Frr.FrrBgpCmd(ctx, fmt.Sprintf("configure terminal\n %s bgp disable-ebgp-connected-route-check\n %s %s %s %s %s %s exit", bgpVrfName, neighlink, neighlinkRe, neighlinkGw, neighlinkOv, neighlinkSr, bgpListen)) + _, err := frr.FrrBgpCmd(ctx, fmt.Sprintf("configure terminal\n %s bgp disable-ebgp-connected-route-check\n %s %s %s %s %s %s exit", bgpVrfName, neighlink, neighlinkRe, neighlinkGw, neighlinkOv, neighlinkSr, bgpListen), false) - if err != nil || checkFrrResult(data, false) { - log.Printf("FRR: Error in conf svi %s %s command %s\n", svi.Name, path.Base(svi.Spec.Vrf), data) - return false + if err != nil { + log.Printf("FRR: Error in conf svi %s %s command %s\n", svi.Name, path.Base(svi.Spec.Vrf), err) + return fmt.Sprintf("FRR: Error in conf svi %s %s command %s\n", svi.Name, path.Base(svi.Spec.Vrf), err), false } - err = Frr.Save(ctx) + err = frr.Save(ctx) if err != nil { log.Printf("FRR(setUpSvi): Failed to run save command: %v\n", err) } - return true + return "", true } - return true + return "", true } // tearDownSvi tears down svi -func tearDownSvi(svi *infradb.Svi) bool { +func tearDownSvi(svi *infradb.Svi) (string, bool) { // linkSvi := fmt.Sprintf("%+v-%+v", path.Base(svi.Spec.Vrf), strings.Split(path.Base(svi.Spec.LogicalBridge), "vlan")[1]) - BrObj, err := infradb.GetLB(svi.Spec.LogicalBridge) + brObj, err := infradb.GetLB(svi.Spec.LogicalBridge) if err != nil { log.Printf("LCI: unable to find key %s and error is %v", svi.Spec.LogicalBridge, err) - return false + return fmt.Sprintf("LCI: unable to find key %s and error is %v", svi.Spec.LogicalBridge, err), false } - linkSvi := fmt.Sprintf("%+v-%+v", path.Base(svi.Spec.Vrf), BrObj.Spec.VlanID) - if svi.Spec.EnableBgp && !reflect.ValueOf(svi.Spec.GatewayIPs).IsZero() { + linkSvi := fmt.Sprintf("%+v-%+v", path.Base(svi.Spec.Vrf), brObj.Spec.VlanID) + if svi.Spec.EnableBgp && len(svi.Spec.GatewayIPs) != 0 { bgpVrfName := fmt.Sprintf("router bgp %+v vrf %s", localas, path.Base(svi.Spec.Vrf)) noNeigh := fmt.Sprintf("no neighbor %s peer-group", linkSvi) - data, err := Frr.FrrBgpCmd(ctx, fmt.Sprintf("configure terminal\n %s\n %s\n exit", bgpVrfName, noNeigh)) - if err != nil || checkFrrResult(data, false) { - log.Printf("FRR: Error in conf Delete vrf/VNI command %s\n", data) - return false + + _, err := frr.FrrBgpCmd(ctx, fmt.Sprintf("configure terminal\n %s\n %s\n exit", bgpVrfName, noNeigh), false) + + if err != nil { + log.Printf("FRR: Error in conf Delete vrf/VNI command %s\n", err) + return fmt.Sprintf("FRR: Error in conf Delete vrf/VNI command %s\n", err), false } - err = Frr.Save(ctx) + err = frr.Save(ctx) if err != nil { log.Printf("FRR(tearDownSvi): Failed to run save command: %v\n", err) } log.Printf("FRR: Executed vtysh -c conf t -c router bgp %+v vrf %s -c no neighbor %s peer-group -c exit\n", localas, path.Base(svi.Spec.Vrf), linkSvi) - return true + return "", true } - return true + return "", true } // tearDownVrf tears down vrf -func tearDownVrf(vrf *infradb.Vrf) bool { +func tearDownVrf(vrf *infradb.Vrf) (string, bool) { // This function must not be executed for the vrf representing the GRD if path.Base(vrf.Name) == "GRD" { - return true + return "", true } - data, err := Frr.FrrZebraCmd(ctx, fmt.Sprintf("show vrf %s vni\n", path.Base(vrf.Name))) + _, err := frr.FrrZebraCmd(ctx, fmt.Sprintf("show vrf %s vni\n", path.Base(vrf.Name)), true) if err != nil { - log.Printf("tearDownVrf : failed to run the command") - } - if checkFrrResult(data, true) { - log.Printf("CP FRR %s\n", data) - return true + log.Printf("FRR: Error %s\n", err) + return "", true } - err = Frr.Save(ctx) + err = frr.Save(ctx) if err != nil { log.Printf("FRR(tearDownVrf): Failed to run save command: %v\n", err) } // Clean up FRR last - if !reflect.ValueOf(vrf.Spec.Vni).IsZero() { + if *vrf.Spec.Vni != 0 { log.Printf("FRR Deleted event") delCmd1 := fmt.Sprintf("no router bgp %+v vrf %s", localas, path.Base(vrf.Name)) delCmd2 := fmt.Sprintf("no vrf %s", path.Base(vrf.Name)) - _, err = Frr.FrrBgpCmd(ctx, fmt.Sprintf("configure terminal\n %s\n exit\n", delCmd1)) + _, err = frr.FrrBgpCmd(ctx, fmt.Sprintf("configure terminal\n %s\n exit\n", delCmd1), false) if err != nil { - return false + log.Printf("FRR: Error %s\n", err) + return fmt.Sprintf("FRR: Error %s\n", err), false } - err = Frr.Save(ctx) + err = frr.Save(ctx) if err != nil { log.Printf("FRR(tearDownVrf): Failed to run save command: %v\n", err) } - _, err = Frr.FrrZebraCmd(ctx, fmt.Sprintf("configure terminal\n %s\n exit\n", delCmd2)) + _, err = frr.FrrZebraCmd(ctx, fmt.Sprintf("configure terminal\n %s\n exit\n", delCmd2), false) if err != nil { - return false + log.Printf("FRR: Error %s\n", err) + return fmt.Sprintf("FRR: Error %s\n", err), false } - err = Frr.Save(ctx) + err = frr.Save(ctx) if err != nil { log.Printf("FRR(tearDownVrf): Failed to run save command: %v\n", err) } log.Printf("FRR: Executed vtysh -c conf t -c %s -c %s -c exit\n", delCmd1, delCmd2) } - return true + return "", true } diff --git a/pkg/utils/frr.go b/pkg/utils/frr.go index 9829feb6..28a3ab57 100644 --- a/pkg/utils/frr.go +++ b/pkg/utils/frr.go @@ -51,8 +51,8 @@ const ( // Frr represents limited subset of functions from Frr package type Frr interface { TelnetDialAndCommunicate(ctx context.Context, command string, port int) (string, error) - FrrZebraCmd(ctx context.Context, command string) (string, error) - FrrBgpCmd(ctx context.Context, command string) (string, error) + FrrZebraCmd(ctx context.Context, command string, cmdTypeShow bool) (string, error) + FrrBgpCmd(ctx context.Context, command string, cmdTypeShow bool) (string, error) Save(context.Context) error Password(conn *telnet.Conn, delim string) error EnterPrivileged(conn *telnet.Conn) error @@ -115,16 +115,47 @@ func (n *FrrWrapper) ExitPrivileged(conn *telnet.Conn) error { return conn.SkipUntil(">") } +// checkFrrResult checks the vrf result +func checkFrrResult(data string, show bool) bool { + if show && data == "" { + return true + } + // // Trying to delete non exist VRF || Trying to delete non exist peer-group + if strings.Contains(data, "Can't find BGP instance") || strings.Contains(data, "Create the peer-group first") { + return false + } + patterns := []string{"error", "warning", "unknown", "ambiguous", "specified does not exist"} + lowerStr := strings.ToLower(data) + for _, pattern := range patterns { + if strings.Contains(lowerStr, pattern) { + return true + } + } + return false +} + // FrrZebraCmd connects to Zebra telnet with password and runs command -func (n *FrrWrapper) FrrZebraCmd(ctx context.Context, command string) (string, error) { +func (n *FrrWrapper) FrrZebraCmd(ctx context.Context, command string, cmdTypeShow bool) (string, error) { // ports defined here https://docs.frrouting.org/en/latest/setup.html#services - return n.TelnetDialAndCommunicate(ctx, command, zebra) + cmdOutput, cmdError := n.TelnetDialAndCommunicate(ctx, command, zebra) + if cmdError != nil { + return "", cmdError + } else if checkFrrResult(cmdOutput, cmdTypeShow) { + return "", fmt.Errorf("%s", cmdOutput) + } + return cmdOutput, cmdError } // FrrBgpCmd connects to Bgp telnet with password and runs command -func (n *FrrWrapper) FrrBgpCmd(ctx context.Context, command string) (string, error) { +func (n *FrrWrapper) FrrBgpCmd(ctx context.Context, command string, cmdTypeShow bool) (string, error) { // ports defined here https://docs.frrouting.org/en/latest/setup.html#services - return n.TelnetDialAndCommunicate(ctx, command, bgpd) + cmdOutput, cmdError := n.TelnetDialAndCommunicate(ctx, command, bgpd) + if cmdError != nil { + return "", cmdError + } else if checkFrrResult(cmdOutput, cmdTypeShow) { + return "", fmt.Errorf("%s", cmdOutput) + } + return cmdOutput, cmdError } // Save command save the current config to /etc/frr/frr.conf