github.com/osrg/gobgp/v3@v3.30.0/internal/pkg/table/adj.go (about)

     1  // Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package table
    17  
    18  import (
    19  	"fmt"
    20  
    21  	"github.com/osrg/gobgp/v3/pkg/log"
    22  	"github.com/osrg/gobgp/v3/pkg/packet/bgp"
    23  )
    24  
    25  type AdjRib struct {
    26  	accepted map[bgp.RouteFamily]int
    27  	table    map[bgp.RouteFamily]*Table
    28  	logger   log.Logger
    29  }
    30  
    31  func NewAdjRib(logger log.Logger, rfList []bgp.RouteFamily) *AdjRib {
    32  	m := make(map[bgp.RouteFamily]*Table)
    33  	for _, f := range rfList {
    34  		m[f] = NewTable(logger, f)
    35  	}
    36  	return &AdjRib{
    37  		table:    m,
    38  		accepted: make(map[bgp.RouteFamily]int),
    39  		logger:   logger,
    40  	}
    41  }
    42  
    43  func (adj *AdjRib) Update(pathList []*Path) {
    44  	for _, path := range pathList {
    45  		if path == nil || path.IsEOR() {
    46  			continue
    47  		}
    48  		rf := path.GetRouteFamily()
    49  		t := adj.table[path.GetRouteFamily()]
    50  		d := t.getOrCreateDest(path.GetNlri(), 0)
    51  		var old *Path
    52  		idx := -1
    53  		for i, p := range d.knownPathList {
    54  			if p.GetNlri().PathIdentifier() == path.GetNlri().PathIdentifier() {
    55  				idx = i
    56  				break
    57  			}
    58  		}
    59  		if idx != -1 {
    60  			old = d.knownPathList[idx]
    61  		}
    62  
    63  		if path.IsWithdraw {
    64  			if idx != -1 {
    65  				d.knownPathList = append(d.knownPathList[:idx], d.knownPathList[idx+1:]...)
    66  				if len(d.knownPathList) == 0 {
    67  					t.deleteDest(d)
    68  				}
    69  				if !old.IsRejected() {
    70  					adj.accepted[rf]--
    71  				}
    72  			}
    73  			path.SetDropped(true)
    74  		} else {
    75  			if idx != -1 {
    76  				if old.IsRejected() && !path.IsRejected() {
    77  					adj.accepted[rf]++
    78  				} else if !old.IsRejected() && path.IsRejected() {
    79  					adj.accepted[rf]--
    80  				}
    81  				if old.Equal(path) {
    82  					path.setTimestamp(old.GetTimestamp())
    83  				}
    84  				d.knownPathList[idx] = path
    85  			} else {
    86  				d.knownPathList = append(d.knownPathList, path)
    87  				if !path.IsRejected() {
    88  					adj.accepted[rf]++
    89  				}
    90  			}
    91  		}
    92  	}
    93  }
    94  
    95  /*
    96  The provided pathList is expected to be the real candidate routes after policy evaluation.
    97  
    98  	For routes that are filtered by policy, there could be a mismatch between display
    99  	and actual rib sent to the peer (if softreset out was not run).
   100  	Only used to display adj-out because we do not maintain a separate adj-out table
   101  */
   102  func (adj *AdjRib) UpdateAdjRibOut(pathList []*Path) {
   103  	for _, path := range pathList {
   104  		if path == nil || path.IsEOR() {
   105  			continue
   106  		}
   107  		t := adj.table[path.GetRouteFamily()]
   108  		d := t.getOrCreateDest(path.GetNlri(), 0)
   109  		d.knownPathList = append(d.knownPathList, path)
   110  	}
   111  }
   112  
   113  func (adj *AdjRib) walk(families []bgp.RouteFamily, fn func(*Destination) bool) {
   114  	for _, f := range families {
   115  		if t, ok := adj.table[f]; ok {
   116  			for _, d := range t.destinations {
   117  				if fn(d) {
   118  					return
   119  				}
   120  			}
   121  		}
   122  	}
   123  }
   124  
   125  func (adj *AdjRib) PathList(rfList []bgp.RouteFamily, accepted bool) []*Path {
   126  	pathList := make([]*Path, 0, adj.Count(rfList))
   127  	adj.walk(rfList, func(d *Destination) bool {
   128  		for _, p := range d.knownPathList {
   129  			if accepted && p.IsRejected() {
   130  				continue
   131  			}
   132  			pathList = append(pathList, p)
   133  		}
   134  		return false
   135  	})
   136  	return pathList
   137  }
   138  
   139  func (adj *AdjRib) Count(rfList []bgp.RouteFamily) int {
   140  	count := 0
   141  	adj.walk(rfList, func(d *Destination) bool {
   142  		count += len(d.knownPathList)
   143  		return false
   144  	})
   145  	return count
   146  }
   147  
   148  func (adj *AdjRib) Accepted(rfList []bgp.RouteFamily) int {
   149  	count := 0
   150  	for _, rf := range rfList {
   151  		if n, ok := adj.accepted[rf]; ok {
   152  			count += n
   153  		}
   154  	}
   155  	return count
   156  }
   157  
   158  func (adj *AdjRib) Drop(rfList []bgp.RouteFamily) []*Path {
   159  	l := make([]*Path, 0, adj.Count(rfList))
   160  	adj.walk(rfList, func(d *Destination) bool {
   161  		for _, p := range d.knownPathList {
   162  			w := p.Clone(true)
   163  			w.SetDropped(true)
   164  			l = append(l, w)
   165  		}
   166  		return false
   167  	})
   168  	for _, rf := range rfList {
   169  		adj.table[rf] = NewTable(adj.logger, rf)
   170  		adj.accepted[rf] = 0
   171  	}
   172  	return l
   173  }
   174  
   175  func (adj *AdjRib) DropStale(rfList []bgp.RouteFamily) []*Path {
   176  	pathList := make([]*Path, 0, adj.Count(rfList))
   177  	adj.walk(rfList, func(d *Destination) bool {
   178  		for _, p := range d.knownPathList {
   179  			if p.IsStale() {
   180  				w := p.Clone(true)
   181  				w.SetDropped(true)
   182  				pathList = append(pathList, w)
   183  			}
   184  		}
   185  		return false
   186  	})
   187  	adj.Update(pathList)
   188  	return pathList
   189  }
   190  
   191  func (adj *AdjRib) StaleAll(rfList []bgp.RouteFamily) []*Path {
   192  	pathList := make([]*Path, 0, adj.Count(rfList))
   193  	adj.walk(rfList, func(d *Destination) bool {
   194  		for i, p := range d.knownPathList {
   195  			n := p.Clone(false)
   196  			n.MarkStale(true)
   197  			n.SetRejected(p.IsRejected())
   198  			d.knownPathList[i] = n
   199  			if !n.IsRejected() {
   200  				pathList = append(pathList, n)
   201  			}
   202  		}
   203  		return false
   204  	})
   205  	return pathList
   206  }
   207  
   208  func (adj *AdjRib) MarkLLGRStaleOrDrop(rfList []bgp.RouteFamily) []*Path {
   209  	pathList := make([]*Path, 0, adj.Count(rfList))
   210  	adj.walk(rfList, func(d *Destination) bool {
   211  		for i, p := range d.knownPathList {
   212  			if p.HasNoLLGR() {
   213  				n := p.Clone(true)
   214  				n.SetDropped(true)
   215  				pathList = append(pathList, n)
   216  			} else {
   217  				n := p.Clone(false)
   218  				n.SetRejected(p.IsRejected())
   219  				n.SetCommunities([]uint32{uint32(bgp.COMMUNITY_LLGR_STALE)}, false)
   220  				if p.IsRejected() {
   221  					d.knownPathList[i] = n
   222  				} else {
   223  					pathList = append(pathList, n)
   224  				}
   225  			}
   226  		}
   227  		return false
   228  	})
   229  	adj.Update(pathList)
   230  	return pathList
   231  }
   232  
   233  func (adj *AdjRib) Select(family bgp.RouteFamily, accepted bool, option ...TableSelectOption) (*Table, error) {
   234  	t, ok := adj.table[family]
   235  	if !ok {
   236  		t = NewTable(adj.logger, family)
   237  	}
   238  	option = append(option, TableSelectOption{adj: true})
   239  	return t.Select(option...)
   240  }
   241  
   242  func (adj *AdjRib) TableInfo(family bgp.RouteFamily) (*TableInfo, error) {
   243  	if _, ok := adj.table[family]; !ok {
   244  		return nil, fmt.Errorf("%s unsupported", family)
   245  	}
   246  	c := adj.Count([]bgp.RouteFamily{family})
   247  	a := adj.Accepted([]bgp.RouteFamily{family})
   248  	return &TableInfo{
   249  		NumDestination: c,
   250  		NumPath:        c,
   251  		NumAccepted:    a,
   252  	}, nil
   253  }