From 11689ed8424cdd6d4c47b3e6f8e07177ab98665b Mon Sep 17 00:00:00 2001 From: DanB Date: Fri, 21 Sep 2018 21:05:24 +0200 Subject: [PATCH] Diameter data provider with support for group filters --- agents/libdmt.go | 43 +++++++++++++++++++++++++++++++++++++++++-- agents/libdmt_test.go | 21 +++++++++++++++++++-- config/rsrparser.go | 5 +++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/agents/libdmt.go b/agents/libdmt.go index 7e074f49f..1e499f112 100644 --- a/agents/libdmt.go +++ b/agents/libdmt.go @@ -151,14 +151,53 @@ func (dP *diameterDP) FieldAsInterface(fldPath []string) (data interface{}, err return nil, err } err = nil // cancel previous err + // lastPath can contain selector inside + lastPath := fldPath[len(fldPath)-1] + var slctr *config.RSRParser + if splt := strings.Split(lastPath, "["); len(splt) != 1 { + lastPath = splt[0] + if splt[1][len(splt[1])-1:] != "]" { + return nil, fmt.Errorf("filter rule <%s> needs to end in ]", splt[1]) + } + fltrStr := splt[1][:len(splt[1])-1] // also strip the last ] + if slctr, err = config.NewRSRParser(fltrStr, true); err != nil { + return nil, err + } + } + pathIface := utils.SliceStringToIface(fldPath) + if slctr != nil { // last path was having selector inside before + pathIface[len(pathIface)-1] = lastPath + } var avps []*diam.AVP if avps, err = dP.m.FindAVPsWithPath( - utils.SliceStringToIface(fldPath), dict.UndefinedVendorID); err != nil { + pathIface, dict.UndefinedVendorID); err != nil { return nil, err } else if len(avps) == 0 { return nil, utils.ErrNotFound } - if data, err = diamAVPAsIface(avps[0]); err != nil { + slectedIdx := 0 // by default we select AVP[0] + if len(avps) != 1 && slctr != nil { + pathIface[len(pathIface)-1] = slctr.AttrName() // search for AVPs which are having common path but different end element + fltrAVPs, err := dP.m.FindAVPsWithPath(pathIface, dict.UndefinedVendorID) + if err != nil { + return nil, err + } else if len(fltrAVPs) == 0 || len(fltrAVPs) != len(avps) { + return nil, utils.ErrFilterNotPassingNoCaps + } + for k, fAVP := range fltrAVPs { + if dataAVP, err := diamAVPAsIface(fAVP); err != nil { + return nil, err + } else if _, err := slctr.ParseValue(dataAVP); err != nil { // filter not passing + if err != utils.ErrFilterNotPassingNoCaps { + return nil, err + } + continue // filter not passing, not really error + } else { + slectedIdx = k // filter passing, found our match, select the index of AVP to return + } + } + } + if data, err = diamAVPAsIface(avps[slectedIdx]); err != nil { return nil, err } dP.cache.Set(fldPath, data, false) diff --git a/agents/libdmt_test.go b/agents/libdmt_test.go index 32cd025a9..830064e84 100644 --- a/agents/libdmt_test.go +++ b/agents/libdmt_test.go @@ -44,6 +44,17 @@ func TestDPFieldAsInterface(t *testing.T) { }), }, }) + m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ + AVP: []*diam.AVP{ + diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(0)), // Subscription-Id-Type + diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("33708000003")), // Subscription-Id-Data + }}) + m.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{ + AVP: []*diam.AVP{ + diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(1)), // Subscription-Id-Type + diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208708000003")), // Subscription-Id-Data + }}) + dP := newDADataProvider(m) eOut := interface{}("simuhuawei;1449573472;00002") if out, err := dP.FieldAsInterface([]string{"Session-Id"}); err != nil { @@ -57,8 +68,14 @@ func TestDPFieldAsInterface(t *testing.T) { } else if eOut != out { t.Errorf("Expecting: %v, received: %v", eOut, out) } - eOut = interface{}(uint32(33)) - if out, err := dP.FieldAsInterface([]string{"Requested-Service-Unit", "CC-Money", "Currency-Code"}); err != nil { + eOut = interface{}("208708000003") // with filter on second group item + if out, err := dP.FieldAsInterface([]string{"Subscription-Id", "Subscription-Id-Data[~Subscription-Id-Type(1)]"}); err != nil { + t.Error(err) + } else if eOut != out { + t.Errorf("Expecting: %v, received: %v", eOut, out) + } + eOut = interface{}("33708000003") + if out, err := dP.FieldAsInterface([]string{"Subscription-Id", "Subscription-Id-Data"}); err != nil { t.Error(err) } else if eOut != out { t.Errorf("Expecting: %v, received: %v", eOut, out) diff --git a/config/rsrparser.go b/config/rsrparser.go index 4892224cf..175aca5c0 100644 --- a/config/rsrparser.go +++ b/config/rsrparser.go @@ -207,6 +207,11 @@ type RSRParser struct { filters utils.RSRFilters // The value to compare when used as filter } +// AttrName exports the attribute name of the RSRParser +func (prsr *RSRParser) AttrName() string { + return prsr.attrName +} + // Compile parses Rules string and repopulates other fields func (prsr *RSRParser) Compile() (err error) { var newPrsr *RSRParser