summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gobgp/cmd/neighbor.go32
-rw-r--r--packet/bgp/bgp.go83
-rw-r--r--packet/bgp/bgp_test.go19
-rw-r--r--server/fsm.go15
4 files changed, 148 insertions, 1 deletions
diff --git a/gobgp/cmd/neighbor.go b/gobgp/cmd/neighbor.go
index 32a01876..5ab7e32c 100644
--- a/gobgp/cmd/neighbor.go
+++ b/gobgp/cmd/neighbor.go
@@ -292,7 +292,37 @@ func showNeighbor(args []string) error {
fmt.Printf(" Remote:\n%s", s)
}
}
-
+ case bgp.BGP_CAP_EXTENDED_NEXTHOP:
+ fmt.Printf(" %s:\t%s\n", c.Code(), support)
+ exnhStr := func(e *bgp.CapExtendedNexthop) string {
+ lines := make([]string, 0, len(e.Tuples))
+ for _, t := range e.Tuples {
+ var nhafi string
+ switch int(t.NexthopAFI) {
+ case bgp.AFI_IP:
+ nhafi = "ipv4"
+ case bgp.AFI_IP6:
+ nhafi = "ipv6"
+ default:
+ nhafi = fmt.Sprintf("%d", t.NexthopAFI)
+ }
+ line := fmt.Sprintf("nlri: %s, nexthop: %s", bgp.AfiSafiToRouteFamily(t.NLRIAFI, uint8(t.NLRISAFI)), nhafi)
+ lines = append(lines, line)
+ }
+ return strings.Join(lines, "\n")
+ }
+ if m := lookup(c, p.Conf.LocalCap); m != nil {
+ e := m.(*bgp.CapExtendedNexthop)
+ if s := exnhStr(e); len(s) > 0 {
+ fmt.Printf(" Local: %s\n", s)
+ }
+ }
+ if m := lookup(c, p.Conf.RemoteCap); m != nil {
+ e := m.(*bgp.CapExtendedNexthop)
+ if s := exnhStr(e); len(s) > 0 {
+ fmt.Printf(" Remote: %s\n", s)
+ }
+ }
default:
fmt.Printf(" %s:\t%s\n", c.Code(), support)
}
diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go
index 3afb7a9e..d7479172 100644
--- a/packet/bgp/bgp.go
+++ b/packet/bgp/bgp.go
@@ -208,6 +208,7 @@ const (
BGP_CAP_MULTIPROTOCOL BGPCapabilityCode = 1
BGP_CAP_ROUTE_REFRESH BGPCapabilityCode = 2
BGP_CAP_CARRYING_LABEL_INFO BGPCapabilityCode = 4
+ BGP_CAP_EXTENDED_NEXTHOP BGPCapabilityCode = 5
BGP_CAP_GRACEFUL_RESTART BGPCapabilityCode = 64
BGP_CAP_FOUR_OCTET_AS_NUMBER BGPCapabilityCode = 65
BGP_CAP_ADD_PATH BGPCapabilityCode = 69
@@ -221,6 +222,7 @@ var CapNameMap = map[BGPCapabilityCode]string{
BGP_CAP_ROUTE_REFRESH: "route-refresh",
BGP_CAP_CARRYING_LABEL_INFO: "carrying-label-info",
BGP_CAP_GRACEFUL_RESTART: "graceful-restart",
+ BGP_CAP_EXTENDED_NEXTHOP: "extended-nexthop",
BGP_CAP_FOUR_OCTET_AS_NUMBER: "4-octet-as",
BGP_CAP_ADD_PATH: "add-path",
BGP_CAP_ENHANCED_ROUTE_REFRESH: "enhanced-route-refresh",
@@ -336,6 +338,85 @@ type CapCarryingLabelInfo struct {
DefaultParameterCapability
}
+type CapExtendedNexthopTuple struct {
+ NLRIAFI uint16
+ NLRISAFI uint16
+ NexthopAFI uint16
+}
+
+func (c *CapExtendedNexthopTuple) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ NLRIAddressFamily RouteFamily `json:"nlri_address_family"`
+ NexthopAddressFamily uint16 `json:"nexthop_address_family"`
+ }{
+ NLRIAddressFamily: AfiSafiToRouteFamily(c.NLRIAFI, uint8(c.NLRISAFI)),
+ NexthopAddressFamily: c.NexthopAFI,
+ })
+}
+
+func NewCapExtendedNexthopTuple(af RouteFamily, nexthop uint16) *CapExtendedNexthopTuple {
+ afi, safi := RouteFamilyToAfiSafi(af)
+ return &CapExtendedNexthopTuple{
+ NLRIAFI: afi,
+ NLRISAFI: uint16(safi),
+ NexthopAFI: nexthop,
+ }
+}
+
+type CapExtendedNexthop struct {
+ DefaultParameterCapability
+ Tuples []*CapExtendedNexthopTuple
+}
+
+func (c *CapExtendedNexthop) DecodeFromBytes(data []byte) error {
+ c.DefaultParameterCapability.DecodeFromBytes(data)
+ data = data[2:]
+ if len(data) < 6 {
+ return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityExtendedNexthop bytes available")
+ }
+ c.Tuples = []*CapExtendedNexthopTuple{}
+ for len(data) >= 6 {
+ t := &CapExtendedNexthopTuple{
+ binary.BigEndian.Uint16(data[0:2]),
+ binary.BigEndian.Uint16(data[2:4]),
+ binary.BigEndian.Uint16(data[4:6]),
+ }
+ c.Tuples = append(c.Tuples, t)
+ data = data[6:]
+ }
+ return nil
+}
+
+func (c *CapExtendedNexthop) Serialize() ([]byte, error) {
+ buf := make([]byte, len(c.Tuples)*6)
+ for i, t := range c.Tuples {
+ binary.BigEndian.PutUint16(buf[i*6:i*6+2], t.NLRIAFI)
+ binary.BigEndian.PutUint16(buf[i*6+2:i*6+4], t.NLRISAFI)
+ binary.BigEndian.PutUint16(buf[i*6+4:i*6+6], t.NexthopAFI)
+ }
+ c.DefaultParameterCapability.CapValue = buf
+ return c.DefaultParameterCapability.Serialize()
+}
+
+func (c *CapExtendedNexthop) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Code BGPCapabilityCode `json:"code"`
+ Tuples []*CapExtendedNexthopTuple `json:"tuples"`
+ }{
+ Code: c.Code(),
+ Tuples: c.Tuples,
+ })
+}
+
+func NewCapExtendedNexthop(tuples []*CapExtendedNexthopTuple) *CapExtendedNexthop {
+ return &CapExtendedNexthop{
+ DefaultParameterCapability{
+ CapCode: BGP_CAP_EXTENDED_NEXTHOP,
+ },
+ tuples,
+ }
+}
+
type CapGracefulRestartTuple struct {
AFI uint16
SAFI uint8
@@ -687,6 +768,8 @@ func DecodeCapability(data []byte) (ParameterCapabilityInterface, error) {
c = &CapRouteRefresh{}
case BGP_CAP_CARRYING_LABEL_INFO:
c = &CapCarryingLabelInfo{}
+ case BGP_CAP_EXTENDED_NEXTHOP:
+ c = &CapExtendedNexthop{}
case BGP_CAP_GRACEFUL_RESTART:
c = &CapGracefulRestart{}
case BGP_CAP_FOUR_OCTET_AS_NUMBER:
diff --git a/packet/bgp/bgp_test.go b/packet/bgp/bgp_test.go
index e6d38873..bb93cee5 100644
--- a/packet/bgp/bgp_test.go
+++ b/packet/bgp/bgp_test.go
@@ -514,6 +514,25 @@ func Test_EVPNIPPrefixRoute(t *testing.T) {
t.Error(len(buf2), n2, buf2)
t.Log(bytes.Equal(buf1, buf2))
}
+}
+
+func Test_CapExtendedNexthop(t *testing.T) {
+ assert := assert.New(t)
+ tuple := NewCapExtendedNexthopTuple(RF_IPv4_UC, AFI_IP6)
+ n1 := NewCapExtendedNexthop([]*CapExtendedNexthopTuple{tuple})
+ buf1, err := n1.Serialize()
+ assert.Nil(err)
+ n2, err := DecodeCapability(buf1)
+ assert.Nil(err)
+ buf2, _ := n2.Serialize()
+ if reflect.DeepEqual(n1, n2) {
+ t.Log("OK")
+ } else {
+ t.Error("Something wrong")
+ t.Error(len(buf1), n1, buf1)
+ t.Error(len(buf2), n2, buf2)
+ t.Log(bytes.Equal(buf1, buf2))
+ }
}
diff --git a/server/fsm.go b/server/fsm.go
index 2f93ff03..e680f8ec 100644
--- a/server/fsm.go
+++ b/server/fsm.go
@@ -561,6 +561,21 @@ func capabilitiesFromConfig(pConf *config.Neighbor) []bgp.ParameterCapabilityInt
caps = append(caps, bgp.NewCapLongLivedGracefulRestart(ltuples))
}
}
+
+ // unnumbered BGP
+ if pConf.Config.NeighborInterface != "" {
+ tuples := []*bgp.CapExtendedNexthopTuple{}
+ families, _ := config.AfiSafis(pConf.AfiSafis).ToRfList()
+ for _, family := range families {
+ if family == bgp.RF_IPv6_UC {
+ continue
+ }
+ tuple := bgp.NewCapExtendedNexthopTuple(family, bgp.AFI_IP6)
+ tuples = append(tuples, tuple)
+ }
+ cap := bgp.NewCapExtendedNexthop(tuples)
+ caps = append(caps, cap)
+ }
return caps
}