summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>2015-07-31 18:51:05 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2015-08-08 20:56:46 +0900
commitbf9e135ba85cad641c3812abace9221cbf5a2615 (patch)
tree435728bd72e93ddfea7a3c02d78cfb1a9c65f16f
parentecd079e318e1c5d5aa2d2f1348a4ad1a37daec37 (diff)
server: support vrf
to add/delete vrf $ gobgp vrf [add|del] <vrf-name> rd <rd> rt [import|export|both] <rt>... show vrf $ gobgp vrf to add/delete a path to a specific vrf $ gobgp vrf <vrf-name> rib [add|del] <prefix> -a <address-family> show paths contained in a specific vrf $ gobgp vrf <vrf-name> rib -a <address-family> Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
-rw-r--r--gobgp/common.go15
-rw-r--r--gobgp/global.go3
-rw-r--r--gobgp/main.go3
-rw-r--r--gobgp/neighbor.go42
-rw-r--r--gobgp/vrf.go402
-rw-r--r--packet/bgp.go67
-rw-r--r--packet/bgp_test.go4
-rw-r--r--policy/policy.go21
-rw-r--r--server/grpc_server.go63
-rw-r--r--server/server.go209
-rw-r--r--table/table_manager.go9
-rw-r--r--table/vrf.go46
12 files changed, 804 insertions, 80 deletions
diff --git a/gobgp/common.go b/gobgp/common.go
index f94b36df..7e4f2b20 100644
--- a/gobgp/common.go
+++ b/gobgp/common.go
@@ -59,6 +59,7 @@ const (
CMD_DUMP = "dump"
CMD_INJECT = "inject"
CMD_RPKI = "rpki"
+ CMD_VRF = "vrf"
)
var subOpts struct {
@@ -288,6 +289,20 @@ func (r roas) Less(i, j int) bool {
return strings.Less(0, 1)
}
+type vrfs []*api.Vrf
+
+func (v vrfs) Len() int {
+ return len(v)
+}
+
+func (v vrfs) Swap(i, j int) {
+ v[i], v[j] = v[j], v[i]
+}
+
+func (v vrfs) Less(i, j int) bool {
+ return v[i].Name < v[j].Name
+}
+
func connGrpc() *grpc.ClientConn {
timeout := grpc.WithTimeout(time.Second)
diff --git a/gobgp/global.go b/gobgp/global.go
index 1ea62ddb..61e1d2f9 100644
--- a/gobgp/global.go
+++ b/gobgp/global.go
@@ -27,8 +27,7 @@ import (
)
func showGlobalRib(args []string) error {
- bogusIp := net.IP{}
- return showNeighborRib(CMD_GLOBAL, bogusIp, args)
+ return showNeighborRib(CMD_GLOBAL, "", args)
}
func getSerizliedRouteTarget(args []string) ([]byte, error) {
diff --git a/gobgp/main.go b/gobgp/main.go
index 08134c4b..1d4463b1 100644
--- a/gobgp/main.go
+++ b/gobgp/main.go
@@ -57,10 +57,11 @@ func main() {
globalCmd := NewGlobalCmd()
neighborCmd := NewNeighborCmd()
+ vrfCmd := NewVrfCmd()
policyCmd := NewPolicyCmd()
monitorCmd := NewMonitorCmd()
mrtCmd := NewMrtCmd()
rpkiCmd := NewRPKICmd()
- rootCmd.AddCommand(globalCmd, neighborCmd, policyCmd, monitorCmd, mrtCmd, rpkiCmd)
+ rootCmd.AddCommand(globalCmd, neighborCmd, vrfCmd, policyCmd, monitorCmd, mrtCmd, rpkiCmd)
rootCmd.Execute()
}
diff --git a/gobgp/neighbor.go b/gobgp/neighbor.go
index bb0755f6..51d82dd3 100644
--- a/gobgp/neighbor.go
+++ b/gobgp/neighbor.go
@@ -395,7 +395,7 @@ func showRoute(pathList []*api.Path, showAge bool, showBest bool, isMonitor bool
}
}
-func showNeighborRib(r string, remoteIP net.IP, args []string) error {
+func showNeighborRib(r string, name string, args []string) error {
var resource api.Resource
switch r {
case CMD_GLOBAL:
@@ -406,8 +406,10 @@ func showNeighborRib(r string, remoteIP net.IP, args []string) error {
resource = api.Resource_ADJ_IN
case CMD_ADJ_OUT:
resource = api.Resource_ADJ_OUT
+ case CMD_VRF:
+ resource = api.Resource_VRF
}
- rt, err := checkAddressFamily(remoteIP)
+ rf, err := checkAddressFamily(net.ParseIP(name))
if err != nil {
return err
}
@@ -415,7 +417,7 @@ func showNeighborRib(r string, remoteIP net.IP, args []string) error {
var prefix string
var host net.IP
if len(args) > 0 {
- if rt != api.AF_IPV4_UC && rt != api.AF_IPV6_UC {
+ if rf != api.AF_IPV4_UC && rf != api.AF_IPV6_UC {
return fmt.Errorf("route filtering is only supported for IPv4/IPv6 unicast routes")
}
_, p, err := net.ParseCIDR(args[0])
@@ -431,13 +433,18 @@ func showNeighborRib(r string, remoteIP net.IP, args []string) error {
arg := &api.Arguments{
Resource: resource,
- Af: rt,
- Name: remoteIP.String(),
+ Af: rf,
+ Name: name,
}
ps := paths{}
showBest := false
showAge := true
+
+ var stream interface {
+ Recv() (*api.Path, error)
+ }
+
switch resource {
case api.Resource_LOCAL, api.Resource_GLOBAL:
showBest = true
@@ -489,9 +496,14 @@ func showNeighborRib(r string, remoteIP net.IP, args []string) error {
showAge = false
fallthrough
case api.Resource_ADJ_IN:
- stream, e := client.GetAdjRib(context.Background(), arg)
- if e != nil {
- return e
+ stream, err = client.GetAdjRib(context.Background(), arg)
+ fallthrough
+ case api.Resource_VRF:
+ if stream == nil {
+ stream, err = client.GetVrf(context.Background(), arg)
+ }
+ if err != nil {
+ return err
}
maxOnes := 0
for {
@@ -538,13 +550,13 @@ func showNeighborRib(r string, remoteIP net.IP, args []string) error {
return nil
}
-func resetNeighbor(cmd string, remoteIP net.IP, args []string) error {
- rt, err := checkAddressFamily(remoteIP)
+func resetNeighbor(cmd string, remoteIP string, args []string) error {
+ rt, err := checkAddressFamily(net.ParseIP(remoteIP))
if err != nil {
return err
}
arg := &api.Arguments{
- Name: remoteIP.String(),
+ Name: remoteIP,
Af: rt,
}
switch cmd {
@@ -560,10 +572,10 @@ func resetNeighbor(cmd string, remoteIP net.IP, args []string) error {
return nil
}
-func stateChangeNeighbor(cmd string, remoteIP net.IP, args []string) error {
+func stateChangeNeighbor(cmd string, remoteIP string, args []string) error {
arg := &api.Arguments{
Af: api.AF_IPV4_UC,
- Name: remoteIP.String(),
+ Name: remoteIP,
}
var err error
switch cmd {
@@ -695,7 +707,7 @@ func NewNeighborCmd() *cobra.Command {
type cmds struct {
names []string
- f func(string, net.IP, []string) error
+ f func(string, string, []string) error
}
c := make([]cmds, 0, 3)
@@ -714,7 +726,7 @@ func NewNeighborCmd() *cobra.Command {
fmt.Println("invalid ip address:", args[len(args)-1])
os.Exit(1)
}
- err := f(cmd.Use, remoteIP, args[:len(args)-1])
+ err := f(cmd.Use, remoteIP.String(), args[:len(args)-1])
if err != nil {
fmt.Println(err)
os.Exit(1)
diff --git a/gobgp/vrf.go b/gobgp/vrf.go
new file mode 100644
index 00000000..26086dde
--- /dev/null
+++ b/gobgp/vrf.go
@@ -0,0 +1,402 @@
+// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/osrg/gobgp/api"
+ "github.com/osrg/gobgp/packet"
+ "github.com/spf13/cobra"
+ "golang.org/x/net/context"
+ "io"
+ "net"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+func getVrfs() (vrfs, error) {
+ arg := &api.Arguments{}
+ stream, err := client.GetVrfs(context.Background(), arg)
+ if err != nil {
+ return nil, err
+ }
+ vs := make(vrfs, 0)
+ for {
+ v, err := stream.Recv()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return nil, err
+ }
+ vs = append(vs, v)
+ }
+
+ sort.Sort(vs)
+
+ return vs, nil
+}
+
+func showVrfs() error {
+ maxLens := []int{20, 20, 20, 20}
+ vrfs, err := getVrfs()
+ if err != nil {
+ return err
+ }
+ if globalOpts.Json {
+ j, _ := json.Marshal(vrfs)
+ fmt.Println(string(j))
+ return nil
+ }
+ lines := make([][]string, 0, len(vrfs))
+ for _, v := range vrfs {
+ name := v.Name
+ rd := bgp.GetRouteDistinguisher(v.Rd).String()
+
+ f := func(bufs [][]byte) (string, error) {
+ ret := make([]string, 0, len(bufs))
+ for _, rt := range bufs {
+ r, err := bgp.ParseExtended(rt)
+ if err != nil {
+ return "", err
+ }
+ ret = append(ret, r.String())
+ }
+ return strings.Join(ret, ", "), nil
+ }
+
+ importRts, _ := f(v.ImportRt)
+ exportRts, _ := f(v.ExportRt)
+ lines = append(lines, []string{name, rd, importRts, exportRts})
+
+ for i, v := range []int{len(name), len(rd), len(importRts), len(exportRts)} {
+ if v > maxLens[i] {
+ maxLens[i] = v + 4
+ }
+ }
+
+ }
+ format := fmt.Sprintf(" %%-%ds %%-%ds %%-%ds %%-%ds\n", maxLens[0], maxLens[1], maxLens[2], maxLens[3])
+ fmt.Printf(format, "Name", "RD", "Import RT", "Export RT")
+ for _, l := range lines {
+ fmt.Printf(format, l[0], l[1], l[2], l[3])
+ }
+ return nil
+}
+
+func showVrf(name string) error {
+ return showNeighborRib(CMD_VRF, name, nil)
+}
+
+func modVrf(typ string, args []string) error {
+ var arg *api.ModVrfArguments
+ switch typ {
+ case CMD_ADD:
+ if len(args) < 6 || args[1] != "rd" || args[3] != "rt" {
+ return fmt.Errorf("Usage: gobgp vrf add <vrf name> rd <rd> rt { import | export | both } <rt>...")
+ }
+ name := args[0]
+ rd, err := bgp.ParseRouteDistinguisher(args[2])
+ if err != nil {
+ return err
+ }
+ cur := ""
+ importRt := make([][]byte, 0)
+ exportRt := make([][]byte, 0)
+ for _, elem := range args[4:] {
+ if elem == "import" || elem == "export" || elem == "both" {
+ cur = elem
+ continue
+ }
+ rt, err := bgp.ParseRouteTarget(elem)
+ if err != nil {
+ return err
+ }
+ buf, err := rt.Serialize()
+ if err != nil {
+ return err
+ }
+ switch cur {
+ case "import":
+ importRt = append(importRt, buf)
+ case "export":
+ exportRt = append(importRt, buf)
+ case "both":
+ importRt = append(importRt, buf)
+ exportRt = append(exportRt, buf)
+ default:
+ return fmt.Errorf("Usage: gobgp vrf add <vrf name> rd <rd> rt { import | export | both } <rt>...")
+ }
+ }
+ buf, _ := rd.Serialize()
+ arg = &api.ModVrfArguments{
+ Operation: api.Operation_ADD,
+ Vrf: &api.Vrf{
+ Name: name,
+ Rd: buf,
+ ImportRt: importRt,
+ ExportRt: exportRt,
+ },
+ }
+ case CMD_DEL:
+ if len(args) != 1 {
+ return fmt.Errorf("Usage: gobgp vrf del <vrf name>")
+ }
+ arg = &api.ModVrfArguments{
+ Operation: api.Operation_DEL,
+ Vrf: &api.Vrf{
+ Name: args[0],
+ },
+ }
+ }
+
+ _, err := client.ModVrf(context.Background(), arg)
+ return err
+}
+
+func modVrfPath(modtype string, vrf string, args []string) error {
+ rf, err := checkAddressFamily(net.IP{})
+ if err != nil {
+ return err
+ }
+
+ var nlri bgp.AddrPrefixInterface
+ var nexthop string
+
+ switch rf {
+ case api.AF_IPV4_UC, api.AF_IPV6_UC:
+ if len(args) != 1 {
+ return fmt.Errorf("usage: vrf %s rib %s <prefix> -a { ipv4 | ipv6 }", vrf, modtype)
+ }
+ ip, net, _ := net.ParseCIDR(args[0])
+ if rf == api.AF_IPV4_UC {
+ if ip.To4() == nil {
+ return fmt.Errorf("invalid ipv4 prefix")
+ }
+ nexthop = "0.0.0.0"
+ ones, _ := net.Mask.Size()
+ nlri = bgp.NewNLRInfo(uint8(ones), ip.String())
+ } else {
+ if ip.To16() == nil {
+ return fmt.Errorf("invalid ipv6 prefix")
+ }
+ nexthop = "::"
+ ones, _ := net.Mask.Size()
+ nlri = bgp.NewIPv6AddrPrefix(uint8(ones), ip.String())
+ }
+ case api.AF_EVPN:
+ if len(args) < 1 {
+ return fmt.Errorf("usage: vrf %s rib %s { macadv | multicast } ... -a evpn", vrf, modtype)
+ }
+ subtype := args[0]
+ args = args[1:]
+
+ switch subtype {
+ case "macadv":
+ if len(args) < 4 {
+ return fmt.Errorf("usage: vrf %s rib %s macadv <mac address> <ip address> <etag> <label> -a evpn", vrf, modtype)
+ }
+ mac, err := net.ParseMAC(args[0])
+ if err != nil {
+ return fmt.Errorf("invalid mac: %s", args[0])
+ }
+ var ip net.IP
+ iplen := 0
+ if args[1] != "0.0.0.0" || args[1] != "::" {
+ ip = net.ParseIP(args[1])
+ if ip == nil {
+ return fmt.Errorf("invalid ip prefix: %s", args[1])
+ }
+ iplen = net.IPv4len * 8
+ if ip.To4() == nil {
+ iplen = net.IPv6len * 8
+ }
+ }
+ eTag, err := strconv.Atoi(args[2])
+ if err != nil {
+ return fmt.Errorf("invalid eTag: %s. err: %s", args[2], err)
+ }
+ label, err := strconv.Atoi(args[3])
+ if err != nil {
+ return fmt.Errorf("invalid label: %s. err: %s", args[3], err)
+ }
+ macIpAdv := &bgp.EVPNMacIPAdvertisementRoute{
+ ESI: bgp.EthernetSegmentIdentifier{
+ Type: bgp.ESI_ARBITRARY,
+ },
+ MacAddressLength: 48,
+ MacAddress: mac,
+ IPAddressLength: uint8(iplen),
+ IPAddress: ip,
+ Labels: []uint32{uint32(label)},
+ ETag: uint32(eTag),
+ }
+ nlri = bgp.NewEVPNNLRI(bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, 0, macIpAdv)
+ case "multicast":
+ if len(args) < 2 {
+ return fmt.Errorf("usage : vrf %s rib %s multicast <ip address> <etag> -a evpn", vrf, modtype)
+ }
+
+ var ip net.IP
+ iplen := 0
+ if args[0] != "0.0.0.0" || args[0] != "::" {
+ ip = net.ParseIP(args[0])
+ if ip == nil {
+ return fmt.Errorf("invalid ip prefix: %s", args[0])
+ }
+ iplen = net.IPv4len * 8
+ if ip.To4() == nil {
+ iplen = net.IPv6len * 8
+ }
+ }
+
+ eTag, err := strconv.Atoi(args[1])
+ if err != nil {
+ return fmt.Errorf("invalid eTag: %s. err: %s", args[1], err)
+ }
+
+ multicastEtag := &bgp.EVPNMulticastEthernetTagRoute{
+ IPAddressLength: uint8(iplen),
+ IPAddress: ip,
+ ETag: uint32(eTag),
+ }
+ nlri = bgp.NewEVPNNLRI(bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG, 0, multicastEtag)
+ default:
+ return fmt.Errorf("usage: vrf %s rib %s { macadv | multicast | ... -a evpn", vrf, modtype)
+ }
+ nexthop = "0.0.0.0"
+ default:
+ return fmt.Errorf("Unsupported route family: %s", rf)
+ }
+
+ arg := &api.ModPathArguments{
+ Resource: api.Resource_VRF,
+ Name: vrf,
+ RawPattrs: make([][]byte, 0),
+ }
+
+ switch modtype {
+ case CMD_ADD:
+ arg.IsWithdraw = false
+ case CMD_DEL:
+ arg.IsWithdraw = true
+ }
+
+ if rf == api.AF_IPV4_UC {
+ arg.RawNlri, _ = nlri.Serialize()
+ n, _ := bgp.NewPathAttributeNextHop(nexthop).Serialize()
+ arg.RawPattrs = append(arg.RawPattrs, n)
+ } else {
+ mpreach, _ := bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}).Serialize()
+ arg.RawPattrs = append(arg.RawPattrs, mpreach)
+ }
+
+ origin, _ := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP).Serialize()
+ arg.RawPattrs = append(arg.RawPattrs, origin)
+
+ stream, err := client.ModPath(context.Background())
+ if err != nil {
+ return err
+ }
+ err = stream.Send(arg)
+ if err != nil {
+ return err
+ }
+ stream.CloseSend()
+
+ res, e := stream.CloseAndRecv()
+ if e != nil {
+ return e
+ }
+ if res.Code != api.Error_SUCCESS {
+ return fmt.Errorf("error: code: %d, msg: %s", res.Code, res.Msg)
+ }
+ return nil
+}
+
+func NewVrfCmd() *cobra.Command {
+
+ ribCmd := &cobra.Command{
+ Use: CMD_RIB,
+ Run: func(cmd *cobra.Command, args []string) {
+ var err error
+ if len(args) == 1 {
+ err = showVrf(args[0])
+ } else {
+ err = fmt.Errorf("usage: gobgp vrf <vrf-name> rib")
+ }
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ },
+ }
+
+ for _, v := range []string{CMD_ADD, CMD_DEL} {
+ cmd := &cobra.Command{
+ Use: v,
+ Run: func(cmd *cobra.Command, args []string) {
+ err := modVrfPath(cmd.Use, args[len(args)-1], args[:len(args)-1])
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ },
+ }
+ ribCmd.AddCommand(cmd)
+ }
+
+ vrfCmdImpl := &cobra.Command{}
+ vrfCmdImpl.AddCommand(ribCmd)
+
+ vrfCmd := &cobra.Command{
+ Use: CMD_VRF,
+ Run: func(cmd *cobra.Command, args []string) {
+ var err error
+ if len(args) == 0 {
+ err = showVrfs()
+ } else if len(args) == 1 {
+ } else {
+ args = append(args[1:], args[0])
+ vrfCmdImpl.SetArgs(args)
+ err = vrfCmdImpl.Execute()
+ }
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ },
+ }
+
+ for _, v := range []string{CMD_ADD, CMD_DEL} {
+ cmd := &cobra.Command{
+ Use: v,
+ Run: func(cmd *cobra.Command, args []string) {
+ err := modVrf(cmd.Use, args)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ },
+ }
+ vrfCmd.AddCommand(cmd)
+ }
+ vrfCmd.PersistentFlags().StringVarP(&subOpts.AddressFamily, "address-family", "a", "", "address family")
+
+ return vrfCmd
+}
diff --git a/packet/bgp.go b/packet/bgp.go
index 9fc3366e..62be473a 100644
--- a/packet/bgp.go
+++ b/packet/bgp.go
@@ -845,7 +845,7 @@ type RouteDistinguisherUnknown struct {
DefaultRouteDistinguisher
}
-func getRouteDistinguisher(data []byte) RouteDistinguisherInterface {
+func GetRouteDistinguisher(data []byte) RouteDistinguisherInterface {
rdtype := binary.BigEndian.Uint16(data[0:2])
switch rdtype {
case BGP_RD_TWO_OCTET_AS:
@@ -1016,7 +1016,7 @@ func (l *LabeledVPNIPAddrPrefix) DecodeFromBytes(data []byte) error {
l.Labels.Labels = []uint32{}
}
data = data[l.Labels.Len():]
- l.RD = getRouteDistinguisher(data)
+ l.RD = GetRouteDistinguisher(data)
data = data[l.RD.Len():]
restbits := int(l.Length) - 8*(l.Labels.Len()+l.RD.Len())
l.decodePrefix(data, uint8(restbits), l.addrlen)
@@ -1208,7 +1208,7 @@ func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte) error {
return fmt.Errorf("Not all RouteTargetMembershipNLRI bytes available")
}
n.AS = binary.BigEndian.Uint32(data[0:4])
- rt, err := parseExtended(data[4:])
+ rt, err := ParseExtended(data[4:])
n.RouteTarget = rt
if err != nil {
return err
@@ -1389,7 +1389,7 @@ type EVPNEthernetAutoDiscoveryRoute struct {
}
func (er *EVPNEthernetAutoDiscoveryRoute) DecodeFromBytes(data []byte) error {
- er.RD = getRouteDistinguisher(data)
+ er.RD = GetRouteDistinguisher(data)
data = data[er.RD.Len():]
err := er.ESI.DecodeFromBytes(data)
if err != nil {
@@ -1403,11 +1403,16 @@ func (er *EVPNEthernetAutoDiscoveryRoute) DecodeFromBytes(data []byte) error {
}
func (er *EVPNEthernetAutoDiscoveryRoute) Serialize() ([]byte, error) {
- buf, err := er.RD.Serialize()
- if err != nil {
- return nil, err
+ var buf []byte
+ var err error
+ if er.RD != nil {
+ buf, err = er.RD.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ buf = make([]byte, 8)
}
-
tbuf, err := er.ESI.Serialize()
if err != nil {
return nil, err
@@ -1441,7 +1446,7 @@ type EVPNMacIPAdvertisementRoute struct {
}
func (er *EVPNMacIPAdvertisementRoute) DecodeFromBytes(data []byte) error {
- er.RD = getRouteDistinguisher(data)
+ er.RD = GetRouteDistinguisher(data)
data = data[er.RD.Len():]
err := er.ESI.DecodeFromBytes(data)
if err != nil {
@@ -1472,9 +1477,15 @@ func (er *EVPNMacIPAdvertisementRoute) DecodeFromBytes(data []byte) error {
}
func (er *EVPNMacIPAdvertisementRoute) Serialize() ([]byte, error) {
- buf, err := er.RD.Serialize()
- if err != nil {
- return nil, err
+ var buf []byte
+ var err error
+ if er.RD != nil {
+ buf, err = er.RD.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ buf = make([]byte, 8)
}
tbuf, err := er.ESI.Serialize()
@@ -1536,7 +1547,7 @@ type EVPNMulticastEthernetTagRoute struct {
}
func (er *EVPNMulticastEthernetTagRoute) DecodeFromBytes(data []byte) error {
- er.RD = getRouteDistinguisher(data)
+ er.RD = GetRouteDistinguisher(data)
data = data[er.RD.Len():]
er.ETag = binary.BigEndian.Uint32(data[0:4])
er.IPAddressLength = data[4]
@@ -1550,9 +1561,15 @@ func (er *EVPNMulticastEthernetTagRoute) DecodeFromBytes(data []byte) error {
}
func (er *EVPNMulticastEthernetTagRoute) Serialize() ([]byte, error) {
- buf, err := er.RD.Serialize()
- if err != nil {
- return nil, err
+ var buf []byte
+ var err error
+ if er.RD != nil {
+ buf, err = er.RD.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ buf = make([]byte, 8)
}
tbuf := make([]byte, 4)
binary.BigEndian.PutUint32(tbuf, er.ETag)
@@ -1593,7 +1610,7 @@ type EVPNEthernetSegmentRoute struct {
}
func (er *EVPNEthernetSegmentRoute) DecodeFromBytes(data []byte) error {
- er.RD = getRouteDistinguisher(data)
+ er.RD = GetRouteDistinguisher(data)
data = data[er.RD.Len():]
er.ESI.DecodeFromBytes(data)
data = data[10:]
@@ -1608,9 +1625,15 @@ func (er *EVPNEthernetSegmentRoute) DecodeFromBytes(data []byte) error {
}
func (er *EVPNEthernetSegmentRoute) Serialize() ([]byte, error) {
- buf, err := er.RD.Serialize()
- if err != nil {
- return nil, err
+ var buf []byte
+ var err error
+ if er.RD != nil {
+ buf, err = er.RD.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ buf = make([]byte, 8)
}
tbuf, err := er.ESI.Serialize()
if err != nil {
@@ -3585,7 +3608,7 @@ type PathAttributeExtendedCommunities struct {
Value []ExtendedCommunityInterface
}
-func parseExtended(data []byte) (ExtendedCommunityInterface, error) {
+func ParseExtended(data []byte) (ExtendedCommunityInterface, error) {
attrType := ExtendedCommunityAttrType(data[0])
transitive := false
switch attrType {
@@ -3648,7 +3671,7 @@ func (p *PathAttributeExtendedCommunities) DecodeFromBytes(data []byte) error {
}
value := p.PathAttribute.Value
for len(value) >= 8 {
- e, err := parseExtended(value)
+ e, err := ParseExtended(value)
if err != nil {
return err
}
diff --git a/packet/bgp_test.go b/packet/bgp_test.go
index 731b9870..e3502d26 100644
--- a/packet/bgp_test.go
+++ b/packet/bgp_test.go
@@ -270,7 +270,7 @@ func Test_RFC5512(t *testing.T) {
buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE)
buf[1] = byte(EC_SUBTYPE_COLOR)
binary.BigEndian.PutUint32(buf[4:], 1000000)
- ec, err := parseExtended(buf)
+ ec, err := ParseExtended(buf)
assert.Equal(nil, err)
assert.Equal("1000000", ec.String())
buf, err = ec.Serialize()
@@ -281,7 +281,7 @@ func Test_RFC5512(t *testing.T) {
buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE)
buf[1] = byte(EC_SUBTYPE_ENCAPSULATION)
binary.BigEndian.PutUint16(buf[6:], uint16(TUNNEL_TYPE_VXLAN))
- ec, err = parseExtended(buf)
+ ec, err = ParseExtended(buf)
assert.Equal(nil, err)
assert.Equal("VXLAN", ec.String())
buf, err = ec.Serialize()
diff --git a/policy/policy.go b/policy/policy.go
index 70d1bbc3..5d0dc631 100644
--- a/policy/policy.go
+++ b/policy/policy.go
@@ -2062,3 +2062,24 @@ func PoliciesToString(reqPolicies []*api.PolicyDefinition) []string {
}
return policies
}
+
+func CanImportToVrf(v *table.Vrf, path *table.Path) bool {
+ f := func(arg []bgp.ExtendedCommunityInterface) []config.ExtCommunity {
+ ret := make([]config.ExtCommunity, 0, len(arg))
+ for _, a := range arg {
+ ret = append(ret, config.ExtCommunity{
+ ExtCommunity: fmt.Sprintf("RT:%s", a.String()),
+ })
+ }
+ return ret
+ }
+ set := config.ExtCommunitySet{
+ ExtCommunitySetName: v.Name,
+ ExtCommunityList: f(v.ImportRt),
+ }
+ matchSet := config.MatchExtCommunitySet{
+ ExtCommunitySet: v.Name,
+ MatchSetOptions: config.MATCH_SET_OPTIONS_TYPE_ANY,
+ }
+ return NewExtCommunityCondition(matchSet, []config.ExtCommunitySet{set}).evaluate(path)
+}
diff --git a/server/grpc_server.go b/server/grpc_server.go
index 17fb6c87..041f0659 100644
--- a/server/grpc_server.go
+++ b/server/grpc_server.go
@@ -48,8 +48,6 @@ const (
REQ_NEIGHBOR_POLICY_DEL_EXPORT
REQ_NEIGHBOR_POLICY_DEL_DISTRIBUTE
REQ_GLOBAL_RIB
- REQ_GLOBAL_ADD
- REQ_GLOBAL_DELETE
REQ_POLICY_PREFIX
REQ_POLICY_PREFIXES
REQ_POLICY_PREFIX_ADD
@@ -85,6 +83,10 @@ const (
REQ_MRT_GLOBAL_RIB
REQ_MRT_LOCAL_RIB
REQ_RPKI
+ REQ_VRF
+ REQ_VRFS
+ REQ_VRF_MOD
+ REQ_MOD_PATH
)
const GRPC_PORT = 8080
@@ -329,16 +331,11 @@ func (s *Server) ModPath(stream api.Grpc_ModPathServer) error {
return err
}
- if arg.Resource != api.Resource_GLOBAL {
+ if arg.Resource != api.Resource_GLOBAL && arg.Resource != api.Resource_VRF {
return fmt.Errorf("unsupported resource: %s", arg.Resource)
}
- reqType := REQ_GLOBAL_ADD
- if arg.IsWithdraw {
- reqType = REQ_GLOBAL_DELETE
- }
-
- req := NewGrpcRequest(reqType, "", bgp.RouteFamily(0), arg)
+ req := NewGrpcRequest(REQ_MOD_PATH, arg.Name, bgp.RouteFamily(0), arg)
s.bgpServerCh <- req
res := <-req.ResponseCh
@@ -641,6 +638,54 @@ func (s *Server) GetRPKI(arg *api.Arguments, stream api.Grpc_GetRPKIServer) erro
return nil
}
+func (s *Server) GetVrf(arg *api.Arguments, stream api.Grpc_GetVrfServer) error {
+ rf, err := convertAf2Rf(arg.Af)
+ if err != nil {
+ return err
+ }
+ req := NewGrpcRequest(REQ_VRF, "", rf, arg)
+ s.bgpServerCh <- req
+
+ for res := range req.ResponseCh {
+ if err := res.Err(); err != nil {
+ log.Debug(err.Error())
+ return err
+ }
+ if err := stream.Send(res.Data.(*api.Path)); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (s *Server) GetVrfs(arg *api.Arguments, stream api.Grpc_GetVrfsServer) error {
+ req := NewGrpcRequest(REQ_VRFS, "", bgp.RouteFamily(0), nil)
+ s.bgpServerCh <- req
+
+ for res := range req.ResponseCh {
+ if err := res.Err(); err != nil {
+ log.Debug(err.Error())
+ return err
+ }
+ if err := stream.Send(res.Data.(*api.Vrf)); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (s *Server) ModVrf(ctx context.Context, arg *api.ModVrfArguments) (*api.Error, error) {
+ none := &api.Error{}
+ req := NewGrpcRequest(REQ_VRF_MOD, "", bgp.RouteFamily(0), arg)
+ s.bgpServerCh <- req
+
+ res := <-req.ResponseCh
+ if err := res.Err(); err != nil {
+ return none, err
+ }
+ return none, nil
+}
+
type GrpcRequest struct {
RequestType int
RemoteAddr string
diff --git a/server/server.go b/server/server.go
index 4cabc7b9..56ef8c68 100644
--- a/server/server.go
+++ b/server/server.go
@@ -831,33 +831,31 @@ func getMacMobilityExtendedCommunity(etag uint32, mac net.HardwareAddr, evpnPath
return nil
}
-func (server *BgpServer) handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*table.Path {
- var isWithdraw bool
+func (server *BgpServer) handleModPathRequest(grpcReq *GrpcRequest, peerInfo *table.PeerInfo) []*table.Path {
var nlri bgp.AddrPrefixInterface
result := &GrpcResponse{}
pattr := make([]bgp.PathAttributeInterface, 0)
extcomms := make([]bgp.ExtendedCommunityInterface, 0)
+ var nexthop string
+ var rf bgp.RouteFamily
- args, ok := grpcReq.Data.(*api.ModPathArguments)
+ arg, ok := grpcReq.Data.(*api.ModPathArguments)
if !ok {
result.ResponseErr = fmt.Errorf("type assertion failed")
goto ERR
}
- if grpcReq.RequestType == REQ_GLOBAL_DELETE {
- isWithdraw = true
- }
- if len(args.RawNlri) > 0 {
+ if len(arg.RawNlri) > 0 {
nlri = &bgp.NLRInfo{}
- err := nlri.DecodeFromBytes(args.RawNlri)
+ err := nlri.DecodeFromBytes(arg.RawNlri)
if err != nil {
result.ResponseErr = err
goto ERR
}
}
- for _, attr := range args.RawPattrs {
+ for _, attr := range arg.RawPattrs {
p, err := bgp.GetPathAttribute(attr)
if err != nil {
result.ResponseErr = err
@@ -871,30 +869,70 @@ func (server *BgpServer) handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *
}
switch p.GetType() {
+ case bgp.BGP_ATTR_TYPE_NEXT_HOP:
+ nexthop = p.(*bgp.PathAttributeNextHop).Value.String()
case bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES:
value := p.(*bgp.PathAttributeExtendedCommunities).Value
if len(value) > 0 {
extcomms = append(extcomms, value...)
}
case bgp.BGP_ATTR_TYPE_MP_REACH_NLRI:
- value := p.(*bgp.PathAttributeMpReachNLRI).Value
- if len(value) != 1 {
+ mpreach := p.(*bgp.PathAttributeMpReachNLRI)
+ if len(mpreach.Value) != 1 {
result.ResponseErr = fmt.Errorf("include only one route in mp_reach_nlri")
goto ERR
}
- nlri = p.(*bgp.PathAttributeMpReachNLRI).Value[0]
- fallthrough
+ nlri = mpreach.Value[0]
+ nexthop = mpreach.Nexthop.String()
default:
pattr = append(pattr, p)
}
}
- if nlri == nil {
- result.ResponseErr = fmt.Errorf("no nlri included")
+ if nlri == nil || nexthop == "" {
+ result.ResponseErr = fmt.Errorf("not found nlri or nexthop")
goto ERR
}
- if bgp.AfiSafiToRouteFamily(nlri.AFI(), nlri.SAFI()) == bgp.RF_EVPN {
+ rf = bgp.AfiSafiToRouteFamily(nlri.AFI(), nlri.SAFI())
+
+ if arg.Resource == api.Resource_VRF {
+ vrfs := server.localRibMap[GLOBAL_RIB_NAME].rib.Vrfs
+ if _, ok := vrfs[arg.Name]; !ok {
+ result.ResponseErr = fmt.Errorf("vrf %s not found", arg.Name)
+ goto ERR
+ }
+ vrf := vrfs[arg.Name]
+
+ switch rf {
+ case bgp.RF_IPv4_UC:
+ n := nlri.(*bgp.NLRInfo)
+ nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(), vrf.Rd)
+ case bgp.RF_IPv6_UC:
+ n := nlri.(*bgp.IPv6AddrPrefix)
+ nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(), vrf.Rd)
+ case bgp.RF_EVPN:
+ n := nlri.(*bgp.EVPNNLRI)
+ switch n.RouteType {
+ case bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT:
+ n.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute).RD = vrf.Rd
+ case bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG:
+ n.RouteTypeData.(*bgp.EVPNMulticastEthernetTagRoute).RD = vrf.Rd
+ }
+ default:
+ result.ResponseErr = fmt.Errorf("unsupported route family for vrf: %s", rf)
+ goto ERR
+ }
+ extcomms = append(extcomms, vrf.ExportRt...)
+ }
+
+ if arg.Resource != api.Resource_VRF && rf == bgp.RF_IPv4_UC {
+ pattr = append(pattr, bgp.NewPathAttributeNextHop(nexthop))
+ } else {
+ pattr = append(pattr, bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}))
+ }
+
+ if rf == bgp.RF_EVPN {
evpnNlri := nlri.(*bgp.EVPNNLRI)
if evpnNlri.RouteType == bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT {
macIpAdv := evpnNlri.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute)
@@ -911,7 +949,7 @@ func (server *BgpServer) handleGlobalRibRequest(grpcReq *GrpcRequest, peerInfo *
pattr = append(pattr, bgp.NewPathAttributeExtendedCommunities(extcomms))
}
- return []*table.Path{table.NewPath(peerInfo, nlri, isWithdraw, pattr, false, time.Now(), args.NoImplicitWithdraw)}
+ return []*table.Path{table.NewPath(peerInfo, nlri, arg.IsWithdraw, pattr, false, time.Now(), arg.NoImplicitWithdraw)}
ERR:
grpcReq.ResponseCh <- result
close(grpcReq.ResponseCh)
@@ -919,8 +957,123 @@ ERR:
}
+func (server *BgpServer) handleVrfMod(arg *api.ModVrfArguments) error {
+ vrfs := server.localRibMap[GLOBAL_RIB_NAME].rib.Vrfs
+ switch arg.Operation {
+ case api.Operation_ADD:
+ if _, ok := vrfs[arg.Vrf.Name]; ok {
+ return fmt.Errorf("vrf %s already exists", arg.Vrf.Name)
+ }
+ rd := bgp.GetRouteDistinguisher(arg.Vrf.Rd)
+ f := func(bufs [][]byte) ([]bgp.ExtendedCommunityInterface, error) {
+ ret := make([]bgp.ExtendedCommunityInterface, 0, len(bufs))
+ for _, rt := range bufs {
+ r, err := bgp.ParseExtended(rt)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, r)
+ }
+ return ret, nil
+ }
+ importRt, err := f(arg.Vrf.ImportRt)
+ if err != nil {
+ return err
+ }
+ exportRt, err := f(arg.Vrf.ImportRt)
+ if err != nil {
+ return err
+ }
+ log.WithFields(log.Fields{
+ "Topic": "Vrf",
+ "Key": arg.Vrf.Name,
+ "Rd": rd,
+ "ImportRt": importRt,
+ "ExportRt": exportRt,
+ }).Debugf("add vrf")
+ vrfs[arg.Vrf.Name] = &table.Vrf{
+ Name: arg.Vrf.Name,
+ Rd: rd,
+ ImportRt: importRt,
+ ExportRt: exportRt,
+ }
+ case api.Operation_DEL:
+ if _, ok := vrfs[arg.Vrf.Name]; !ok {
+ return fmt.Errorf("vrf %s not found", arg.Vrf.Name)
+ }
+ vrf := vrfs[arg.Vrf.Name]
+ log.WithFields(log.Fields{
+ "Topic": "Vrf",
+ "Key": vrf.Name,
+ "Rd": vrf.Rd,
+ "ImportRt": vrf.ImportRt,
+ "ExportRt": vrf.ExportRt,
+ }).Debugf("delete vrf")
+ delete(vrfs, arg.Vrf.Name)
+ default:
+ return fmt.Errorf("unknown operation:", arg.Operation)
+ }
+ return nil
+}
+
+func (server *BgpServer) handleVrfRequest(req *GrpcRequest) []*table.Path {
+ var msgs []*table.Path
+ result := &GrpcResponse{}
+
+ switch req.RequestType {
+ case REQ_VRF:
+ arg := req.Data.(*api.Arguments)
+ rib := server.localRibMap[GLOBAL_RIB_NAME].rib
+ vrfs := rib.Vrfs
+ if _, ok := vrfs[arg.Name]; !ok {
+ result.ResponseErr = fmt.Errorf("vrf %s not found", arg.Name)
+ break
+ }
+ var rf bgp.RouteFamily
+ switch req.RouteFamily {
+ case bgp.RF_IPv4_UC:
+ rf = bgp.RF_IPv4_VPN
+ case bgp.RF_IPv6_UC:
+ rf = bgp.RF_IPv6_VPN
+ case bgp.RF_EVPN:
+ rf = bgp.RF_EVPN
+ default:
+ result.ResponseErr = fmt.Errorf("unsupported route family: %s", req.RouteFamily)
+ break
+ }
+ for _, path := range rib.GetPathList(rf) {
+ ok := policy.CanImportToVrf(vrfs[arg.Name], path)
+ if !ok {
+ continue
+ }
+ req.ResponseCh <- &GrpcResponse{
+ Data: path.ToApiStruct(),
+ }
+ }
+ goto END
+ case REQ_VRFS:
+ vrfs := server.localRibMap[GLOBAL_RIB_NAME].rib.Vrfs
+ for _, vrf := range vrfs {
+ req.ResponseCh <- &GrpcResponse{
+ Data: vrf.ToApiStruct(),
+ }
+ }
+ goto END
+ case REQ_VRF_MOD:
+ arg := req.Data.(*api.ModVrfArguments)
+ result.ResponseErr = server.handleVrfMod(arg)
+ default:
+ result.ResponseErr = fmt.Errorf("unknown request type:", req.RequestType)
+ }
+
+ req.ResponseCh <- result
+END:
+ close(req.ResponseCh)
+ return msgs
+}
+
func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
- msgs := make([]*SenderMsg, 0)
+ var msgs []*SenderMsg
switch grpcReq.RequestType {
case REQ_GLOBAL_RIB:
@@ -933,14 +1086,14 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
}
close(grpcReq.ResponseCh)
- case REQ_GLOBAL_ADD, REQ_GLOBAL_DELETE:
+ case REQ_MOD_PATH:
pi := &table.PeerInfo{
AS: server.bgpConfig.Global.GlobalConfig.As,
LocalID: server.bgpConfig.Global.GlobalConfig.RouterId,
}
- pathList := server.handleGlobalRibRequest(grpcReq, pi)
+ pathList := server.handleModPathRequest(grpcReq, pi)
if len(pathList) > 0 {
- msgs = append(msgs, server.propagateUpdate("", false, pathList)...)
+ msgs = server.propagateUpdate("", false, pathList)
grpcReq.ResponseCh <- &GrpcResponse{}
close(grpcReq.ResponseCh)
}
@@ -1011,7 +1164,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
break
}
m := bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN, nil)
- msgs = append(msgs, newSenderMsg(peer, []*bgp.BGPMessage{m}))
+ msgs = []*SenderMsg{newSenderMsg(peer, []*bgp.BGPMessage{m})}
grpcReq.ResponseCh <- &GrpcResponse{}
close(grpcReq.ResponseCh)
@@ -1022,7 +1175,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
}
peer.fsm.idleHoldTime = peer.conf.Timers.TimersConfig.IdleHoldTimeAfterReset
m := bgp.NewBGPNotificationMessage(bgp.BGP_ERROR_CEASE, bgp.BGP_ERROR_SUB_ADMINISTRATIVE_RESET, nil)
- msgs = append(msgs, newSenderMsg(peer, []*bgp.BGPMessage{m}))
+ msgs = []*SenderMsg{newSenderMsg(peer, []*bgp.BGPMessage{m})}
grpcReq.ResponseCh <- &GrpcResponse{}
close(grpcReq.ResponseCh)
@@ -1032,8 +1185,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
break
}
pathList := peer.adjRib.GetInPathList(grpcReq.RouteFamily)
- msgs = append(msgs, server.propagateUpdate(peer.conf.NeighborConfig.NeighborAddress.String(),
- peer.isRouteServerClient(), pathList)...)
+ msgs = server.propagateUpdate(peer.conf.NeighborConfig.NeighborAddress.String(), peer.isRouteServerClient(), pathList)
if grpcReq.RequestType == REQ_NEIGHBOR_SOFT_RESET_IN {
grpcReq.ResponseCh <- &GrpcResponse{}
@@ -1048,7 +1200,7 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
}
pathList := peer.adjRib.GetOutPathList(grpcReq.RouteFamily)
msgList := table.CreateUpdateMsgFromPaths(pathList)
- msgs = append(msgs, newSenderMsg(peer, msgList))
+ msgs = []*SenderMsg{newSenderMsg(peer, msgList)}
grpcReq.ResponseCh <- &GrpcResponse{}
close(grpcReq.ResponseCh)
@@ -1239,6 +1391,11 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg {
server.handleMrt(grpcReq)
case REQ_RPKI:
server.roaClient.handleGRPC(grpcReq)
+ case REQ_VRF, REQ_VRFS, REQ_VRF_MOD:
+ pathList := server.handleVrfRequest(grpcReq)
+ if len(pathList) > 0 {
+ msgs = server.propagateUpdate("", false, pathList)
+ }
default:
errmsg := fmt.Errorf("Unknown request type: %v", grpcReq.RequestType)
result := &GrpcResponse{
diff --git a/table/table_manager.go b/table/table_manager.go
index 2b34f2c6..41630246 100644
--- a/table/table_manager.go
+++ b/table/table_manager.go
@@ -113,17 +113,20 @@ func ProcessMessage(m *bgp.BGPMessage, peerInfo *PeerInfo) []*Path {
type TableManager struct {
Tables map[bgp.RouteFamily]*Table
+ Vrfs map[string]*Vrf
localAsn uint32
owner string
}
func NewTableManager(owner string, rfList []bgp.RouteFamily) *TableManager {
- t := &TableManager{}
- t.Tables = make(map[bgp.RouteFamily]*Table)
+ t := &TableManager{
+ Tables: make(map[bgp.RouteFamily]*Table),
+ Vrfs: make(map[string]*Vrf),
+ owner: owner,
+ }
for _, rf := range rfList {
t.Tables[rf] = NewTable(rf)
}
- t.owner = owner
return t
}
diff --git a/table/vrf.go b/table/vrf.go
new file mode 100644
index 00000000..3833ecac
--- /dev/null
+++ b/table/vrf.go
@@ -0,0 +1,46 @@
+// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package table
+
+import (
+ "github.com/osrg/gobgp/api"
+ "github.com/osrg/gobgp/packet"
+)
+
+type Vrf struct {
+ Name string
+ Rd bgp.RouteDistinguisherInterface
+ ImportRt []bgp.ExtendedCommunityInterface
+ ExportRt []bgp.ExtendedCommunityInterface
+}
+
+func (v *Vrf) ToApiStruct() *api.Vrf {
+ f := func(rts []bgp.ExtendedCommunityInterface) [][]byte {
+ ret := make([][]byte, 0, len(rts))
+ for _, rt := range rts {
+ b, _ := rt.Serialize()
+ ret = append(ret, b)
+ }
+ return ret
+ }
+ rd, _ := v.Rd.Serialize()
+ return &api.Vrf{
+ Name: v.Name,
+ Rd: rd,
+ ImportRt: f(v.ImportRt),
+ ExportRt: f(v.ExportRt),
+ }
+}