diff --git a/cmd/gobgp/global.go b/cmd/gobgp/global.go index 758c08712..9d36da174 100644 --- a/cmd/gobgp/global.go +++ b/cmd/gobgp/global.go @@ -1295,9 +1295,9 @@ func parseMUPArgs(args []string, afi uint16, nexthop string) (bgp.AddrPrefixInte return nil, nil, nil, fmt.Errorf("invalid subtype. expect [isd|dsd|t1st|t2st] but %s", subtype) } -func parseLsLinkProtocol(args []string, afi uint16) (bgp.AddrPrefixInterface, error) { +func parseLsLinkProtocol(args []string, afi uint16) (bgp.AddrPrefixInterface, *bgp.PathAttributeLs, error) { if len(args) < 2 { - return nil, fmt.Errorf("lack of protocolType") + return nil, nil, fmt.Errorf("lack of protocolType") } protocolType := args[1] switch protocolType { @@ -1305,15 +1305,15 @@ func parseLsLinkProtocol(args []string, afi uint16) (bgp.AddrPrefixInterface, er case "bgp": return parseLsLinkNLRIType(args, afi) } - return nil, fmt.Errorf("invalid protocolType. expect [bgp] but %s", protocolType) + return nil, nil, fmt.Errorf("invalid protocolType. expect [bgp] but %s", protocolType) } -func parseLsLinkNLRIType(args []string, afi uint16) (bgp.AddrPrefixInterface, error) { +func parseLsLinkNLRIType(args []string, afi uint16) (bgp.AddrPrefixInterface, *bgp.PathAttributeLs, error) { // Format: // identifier asn bgp-ls-id ospf req := 26 if len(args) < req { - return nil, fmt.Errorf("%d args required at least, but got %d", req, len(args)) + return nil, nil, fmt.Errorf("%d args required at least, but got %d", req, len(args)) } m, err := extractReserved(args, map[string]int{ @@ -1332,29 +1332,34 @@ func parseLsLinkNLRIType(args []string, afi uint16) (bgp.AddrPrefixInterface, er "ipv6-neighbor-address": paramSingle, "sid": paramSingle, "sid-type": paramSingle, + "v-flag": paramFlag, + "l-flag": paramFlag, + "b-flag": paramFlag, + "p-flag": paramFlag, + "weight": paramSingle, }) if err != nil { - return nil, err + return nil, nil, err } identifier, err := strconv.ParseUint(m["identifier"][0], 10, 64) if err != nil { - return nil, err + return nil, nil, err } localAsn, err := strconv.ParseUint(m["local-asn"][0], 10, 64) if err != nil { - return nil, err + return nil, nil, err } localBgpLsId, err := strconv.ParseUint(m["local-bgp-ls-id"][0], 10, 64) if err != nil { - return nil, err + return nil, nil, err } localBgpConfederationMember, err := strconv.ParseUint(m["local-bgp-confederation-member"][0], 10, 64) if err != nil { - return nil, err + return nil, nil, err } lnd := &bgp.LsNodeDescriptor{ @@ -1368,17 +1373,17 @@ func parseLsLinkNLRIType(args []string, afi uint16) (bgp.AddrPrefixInterface, er } RemoteAsn, err := strconv.ParseUint(m["remote-asn"][0], 10, 64) if err != nil { - return nil, err + return nil, nil, err } RemoteBgpLsId, err := strconv.ParseUint(m["remote-bgp-ls-id"][0], 10, 64) if err != nil { - return nil, err + return nil, nil, err } RemoteBgpConfederationMember, err := strconv.ParseUint(m["remote-bgp-confederation-member"][0], 10, 64) if err != nil { - return nil, err + return nil, nil, err } rnd := &bgp.LsNodeDescriptor{ @@ -1414,9 +1419,94 @@ func parseLsLinkNLRIType(args []string, afi uint16) (bgp.AddrPrefixInterface, er rndTLV := bgp.NewLsTLVNodeDescriptor(rnd, bgp.LS_TLV_REMOTE_NODE_DESC) ldTLV := bgp.NewLsLinkTLVs(ld) + sidTypeString := m["sid-type"][0] + + sidtype := lsTLVTypeSelect(sidTypeString) + + var peerNodeFlag uint8 + + if _, ok := m["v-flag"]; ok { + peerNodeFlag = peerNodeFlag | 0x80 + } + if _, ok := m["l-flag"]; ok { + peerNodeFlag = peerNodeFlag | 0x40 + } + if _, ok := m["b-flag"]; ok { + peerNodeFlag = peerNodeFlag | 0x20 + } + if _, ok := m["p-flag"]; ok { + peerNodeFlag = peerNodeFlag | 0x10 + } + + lsTLVWeight, err := strconv.ParseUint(m["weight"][0], 10, 64) + if err != nil { + return nil, nil, err + } + lsTLVSid, err := strconv.ParseUint(m["sid"][0], 10, 64) + if err != nil { + return nil, nil, err + } + + const lsTlvLen = 7 + const t = bgp.BGP_ATTR_TYPE_LS + const pathAttrHdrLen = 4 + var tlvs []bgp.LsTLVInterface + length := uint16(pathAttrHdrLen + lsTlvLen) + + switch sidtype { + case bgp.LS_TLV_PEER_NODE_SID: + + lsTLV := &bgp.LsTLVPeerNodeSID{ + LsTLV: bgp.LsTLV{ + Type: sidtype, + Length: uint16(lsTlvLen), + }, + Flags: peerNodeFlag, + Weight: uint8(lsTLVWeight), + SID: uint32(lsTLVSid), + } + tlvs = append(tlvs, lsTLV) + case bgp.LS_TLV_ADJACENCY_SID: + lsTLV := &bgp.LsTLVAdjacencySID{ + LsTLV: bgp.LsTLV{ + Type: sidtype, + Length: uint16(lsTlvLen), + }, + Flags: peerNodeFlag, + Weight: uint8(lsTLVWeight), + SID: uint32(lsTLVSid), + } + tlvs = append(tlvs, lsTLV) + case bgp.LS_TLV_PEER_SET_SID: + lsTLV := &bgp.LsTLVPeerSetSID{ + LsTLV: bgp.LsTLV{ + Type: sidtype, + Length: uint16(lsTlvLen), + }, + Flags: peerNodeFlag, + Weight: uint8(lsTLVWeight), + SID: uint32(lsTLVSid), + } + tlvs = append(tlvs, lsTLV) + } + + pathAttributeLs := &bgp.PathAttributeLs{ + PathAttribute: bgp.PathAttribute{ + Flags: bgp.PathAttrFlags[t], + Type: t, + Length: length, + }, + TLVs: tlvs, + } + len := len(ldTLV) + var sum int + for i := 0; i < len; i++ { + sum += ldTLV[i].Len() + } + const CodeLen = 1 const topologyLen = 8 - LsNLRIhdrlen := lndTLV.Len() + rndTLV.Len() + topologyLen + CodeLen + LsNLRIhdrlen := sum + lndTLV.Len() + rndTLV.Len() + topologyLen + CodeLen lsNlri := bgp.LsNLRI{ NLRIType: bgp.LS_NLRI_TYPE_NODE, Length: uint16(LsNLRIhdrlen), @@ -1433,12 +1523,26 @@ func parseLsLinkNLRIType(args []string, afi uint16) (bgp.AddrPrefixInterface, er LinkDesc: ldTLV, }, } - return nlri, nil + return nlri, pathAttributeLs, nil } -func parseLsArgs(args []string, afi uint16) (bgp.AddrPrefixInterface, error) { +func lsTLVTypeSelect(s string) bgp.LsTLVType { + switch s { + case "node": + return bgp.LS_TLV_PEER_NODE_SID + case "adj": + return bgp.LS_TLV_ADJACENCY_SID + case "set": + return bgp.LS_TLV_PEER_SET_SID + } + + return bgp.LS_TLV_UNKNOWN + +} + +func parseLsArgs(args []string, afi uint16) (bgp.AddrPrefixInterface, *bgp.PathAttributeLs, error) { if len(args) < 1 { - return nil, fmt.Errorf("lack of nlriType") + return nil, nil, fmt.Errorf("lack of nlriType") } nlriType := args[0] switch nlriType { @@ -1447,7 +1551,7 @@ func parseLsArgs(args []string, afi uint16) (bgp.AddrPrefixInterface, error) { // TODO: case node / IPv4 Topology Prefix / IPv6 Topology Prefix / TE Policy / SRv6 SID } - return nil, fmt.Errorf("invalid nlriType. expect [link] but %s", nlriType) + return nil, nil, fmt.Errorf("invalid nlriType. expect [link] but %s", nlriType) } func extractOrigin(args []string) ([]string, bgp.PathAttributeInterface, error) { @@ -1691,6 +1795,7 @@ func parsePath(rf bgp.RouteFamily, args []string) (*api.Path, error) { var nlri bgp.AddrPrefixInterface var extcomms []string var psid *bgp.PathAttributePrefixSID + var ls *bgp.PathAttributeLs var err error attrs := make([]bgp.PathAttributeInterface, 0, 1) @@ -1842,13 +1947,16 @@ func parsePath(rf bgp.RouteFamily, args []string) (*api.Path, error) { case bgp.RF_MUP_IPv6: nlri, psid, extcomms, err = parseMUPArgs(args, bgp.AFI_IP6, nexthop) case bgp.RF_LS: - nlri, err = parseLsArgs(args, bgp.AFI_LS) + nlri, ls, err = parseLsArgs(args, bgp.AFI_LS) default: return nil, fmt.Errorf("unsupported route family: %s", rf) } if err != nil { return nil, err } + if ls != nil { + attrs = append(attrs, ls) + } if rf == bgp.RF_IPv4_UC && net.ParseIP(nexthop).To4() != nil { attrs = append(attrs, bgp.NewPathAttributeNextHop(nexthop)) @@ -1930,10 +2038,10 @@ func modPath(resource string, name, modtype string, args []string) error { helpErrMap := map[bgp.RouteFamily]error{} baseHelpMsgFmt := fmt.Sprintf(`error: %s usage: %s rib -a %%s %s %%s [origin { igp | egp | incomplete }] [aspath ] [nexthop
] [med ] [local-pref ] [community ] [aigp metric ] [large-community ] [aggregator ] - : [,], - : xxx:xxx|internet|planned-shut|accept-own|route-filter-translated-v4|route-filter-v4|route-filter-translated-v6|route-filter-v6|llgr-stale|no-llgr|blackhole|no-export|no-advertise|no-export-subconfed|no-peer, - : xxx:xxx:xxx[,], - : :
`, + : [,], + : xxx:xxx|internet|planned-shut|accept-own|route-filter-translated-v4|route-filter-v4|route-filter-translated-v6|route-filter-v6|llgr-stale|no-llgr|blackhole|no-export|no-advertise|no-export-subconfed|no-peer, + : xxx:xxx:xxx[,], + : :
`, err, cmdstr, //