summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJieJhih Jhang <aawer12345tw@yahoo.com.tw>2019-03-29 17:12:10 +0800
committerFUJITA Tomonori <fujita.tomonori@gmail.com>2019-04-11 07:30:35 +0900
commit42feaea2a0bfc3deb1becdc8c06e4bad44a4b52c (patch)
tree963e4c813a0686ef44acf2a593ea6b33cf1be355
parentfa5878f6f306e1f8abfc58c4e421a55ead51854d (diff)
cmd/gobgp: Parse evpn IPMSI parameter
-rw-r--r--cmd/gobgp/global.go56
-rw-r--r--docs/sources/evpn.md31
-rw-r--r--pkg/packet/bgp/bgp.go7
3 files changed, 92 insertions, 2 deletions
diff --git a/cmd/gobgp/global.go b/cmd/gobgp/global.go
index fe53242f..9017c0d3 100644
--- a/cmd/gobgp/global.go
+++ b/cmd/gobgp/global.go
@@ -829,6 +829,60 @@ func parseEvpnIPPrefixArgs(args []string) (bgp.AddrPrefixInterface, []string, er
return bgp.NewEVPNNLRI(bgp.EVPN_IP_PREFIX, r), extcomms, nil
}
+func parseEvpnIPMSIArgs(args []string) (bgp.AddrPrefixInterface, []string, error) {
+ // Format:
+ // etag <etag> rd <rd> [rt <rt>...] [encap <encap type>]
+ req := 4
+ if len(args) < req {
+ return nil, nil, fmt.Errorf("%d args required at least, but got %d", req, len(args))
+ }
+ m, err := extractReserved(args, map[string]int{
+ "etag": paramSingle,
+ "rd": paramSingle,
+ "rt": paramSingle,
+ "encap": paramSingle})
+ if err != nil {
+ return nil, nil, err
+ }
+ for _, f := range []string{"etag", "rd"} {
+ for len(m[f]) == 0 {
+ return nil, nil, fmt.Errorf("specify %s", f)
+ }
+ }
+
+ rd, err := bgp.ParseRouteDistinguisher(m["rd"][0])
+ if err != nil {
+ return nil, nil, err
+ }
+
+ e, err := strconv.ParseUint(m["etag"][0], 10, 32)
+ if err != nil {
+ return nil, nil, fmt.Errorf("invalid etag: %s: %s", m["etag"][0], err)
+ }
+ etag := uint32(e)
+
+ extcomms := make([]string, 0)
+ if len(m["rt"]) > 0 {
+ extcomms = append(extcomms, "rt")
+ extcomms = append(extcomms, m["rt"]...)
+ }
+ ec, err := bgp.ParseExtendedCommunity(bgp.EC_SUBTYPE_SOURCE_AS, m["rt"][0])
+ if err != nil {
+ return nil, nil, fmt.Errorf("route target parse failed")
+ }
+
+ if len(m["encap"]) > 0 {
+ extcomms = append(extcomms, "encap", m["encap"][0])
+ }
+
+ r := &bgp.EVPNIPMSIRoute{
+ RD: rd,
+ ETag: etag,
+ EC: ec,
+ }
+ return bgp.NewEVPNNLRI(bgp.EVPN_I_PMSI, r), extcomms, nil
+}
+
func parseEvpnArgs(args []string) (bgp.AddrPrefixInterface, []string, error) {
if len(args) < 1 {
return nil, nil, fmt.Errorf("lack of args. need 1 but %d", len(args))
@@ -846,6 +900,8 @@ func parseEvpnArgs(args []string) (bgp.AddrPrefixInterface, []string, error) {
return parseEvpnEthernetSegmentArgs(args)
case "prefix":
return parseEvpnIPPrefixArgs(args)
+ case "i-pmsi":
+ return parseEvpnIPMSIArgs(args)
}
return nil, nil, fmt.Errorf("invalid subtype. expect [macadv|multicast|prefix] but %s", subtype)
}
diff --git a/docs/sources/evpn.md b/docs/sources/evpn.md
index db139231..e84b615d 100644
--- a/docs/sources/evpn.md
+++ b/docs/sources/evpn.md
@@ -239,6 +239,37 @@ $ gobgp global rib -a evpn prefix
$ gobgp global rib -a evpn del prefix 10.0.0.0/24 172.16.0.1 esi MSTP aa:aa:aa:aa:aa:aa 100 etag 200 label 300 rd 1.1.1.1:65000
```
+### I-PMSI Route
+
+```bash
+# Add a route
+$ gobgp global rib -a evpn add i-pmsi etag <etag> rd <rd> [rt <rt>...] [encap <encap type>]
+
+# Show routes
+$ gobgp global rib -a evpn [i-pmsi]
+
+# Delete route
+$ gobgp global rib -a evpn del i-pmsi etag <etag> rd <rd>
+```
+
+#### Example - I-PMSI Route
+
+```bash
+# Simple case
+$ gobgp global rib -a evpn add i-pmsi etag 100 rd 1.1.1.1:65000 rt 65000:200
+$ gobgp global rib -a evpn i-pmsi
+ Network Labels Next Hop AS_PATH Age Attrs
+*> [type:I-PMSI][rd:1.1.1.1:65000][etag:100][EC:65000:0] 0.0.0.0 00:00:00 [{Origin: ?}
+$ gobgp global rib -a evpn del i-pmsi 10.0.0.0/24 etag 100 rd 1.1.1.1:65000
+
+# With optionals
+$ gobgp global rib -a evpn add i-pmsi etag 100 rd 1.1.1.1:65000 rt 65000:200 encap vxlan pmsi ingress-repl 100 1.1.1.1
+$ gobgp global rib -a evpn i-pmsi
+ Network Labels Next Hop AS_PATH Age Attrs
+*> [type:I-PMSI][rd:1.1.1.1:65000][etag:100][EC:65000:0] 0.0.0.0 00:00:00 [{Origin: ?} {Pmsi: type: ingress-repl, label: 100, tunnel-id: 1.1.1.1} {Extcomms: [65000:200], [VXLAN]}]
+$ gobgp global rib -a evpn del i-pmsi etag 200 rd 1.1.1.1:65000
+```
+
## Reference
### Router's MAC Option
diff --git a/pkg/packet/bgp/bgp.go b/pkg/packet/bgp/bgp.go
index 0aae3559..4d899f24 100644
--- a/pkg/packet/bgp/bgp.go
+++ b/pkg/packet/bgp/bgp.go
@@ -2933,7 +2933,7 @@ func (er *EVPNIPMSIRoute) DecodeFromBytes(data []byte) error {
er.ETag = binary.BigEndian.Uint32(data[0:4])
data = data[4:]
- ec, err := ParseExtended(data[0:64])
+ ec, err := ParseExtended(data[0:8])
if err != nil {
return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Parse extended community interface failed"))
}
@@ -2967,7 +2967,7 @@ func (er *EVPNIPMSIRoute) String() string {
if er.EC != nil {
ec = er.EC.String()
}
- return fmt.Sprintf("[rd:%s][etag:%d][EC]:%s]", er.RD, er.ETag, ec)
+ return fmt.Sprintf("[type:I-PMSI][rd:%s][etag:%d][EC:%s]", er.RD, er.ETag, ec)
}
func (er *EVPNIPMSIRoute) MarshalJSON() ([]byte, error) {
@@ -10011,6 +10011,9 @@ func ParseExtendedCommunity(subtype ExtendedCommunityAttrSubType, com string) (E
return nil, err
}
localAdmin, _ := strconv.ParseUint(elems[10], 10, 32)
+ if subtype == EC_SUBTYPE_SOURCE_AS {
+ localAdmin = 0
+ }
ip := net.ParseIP(elems[1])
isTransitive := true
switch {