diff --git a/protocols/bgp/packet/BUILD.bazel b/protocols/bgp/packet/BUILD.bazel
index f9886e41d0eea9ee21bac03dc902ad7f4218b131..9ea14d6607ee4dfe18b135e29c8de7c9d3a4b8a3 100644
--- a/protocols/bgp/packet/BUILD.bazel
+++ b/protocols/bgp/packet/BUILD.bazel
@@ -4,7 +4,9 @@ go_library(
     name = "go_default_library",
     srcs = [
         "bgp.go",
+        "decode_options.go",
         "decoder.go",
+        "encode_options.go",
         "encoder.go",
         "helper.go",
         "mp_reach_nlri.go",
diff --git a/protocols/bgp/packet/decoder.go b/protocols/bgp/packet/decoder.go
index cd951463a15215bd6aaa43e8799e59c95cee549b..0d719fc04c20779ae818e21e756ba925c4bb4e5e 100644
--- a/protocols/bgp/packet/decoder.go
+++ b/protocols/bgp/packet/decoder.go
@@ -6,12 +6,11 @@ import (
 	"fmt"
 	"net"
 
-	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 	"github.com/taktv6/tflow2/convert"
 )
 
 // Decode decodes a BGP message
-func Decode(buf *bytes.Buffer, opt *types.Options) (*BGPMessage, error) {
+func Decode(buf *bytes.Buffer, opt *DecodeOptions) (*BGPMessage, error) {
 	hdr, err := decodeHeader(buf)
 	if err != nil {
 		return nil, fmt.Errorf("Failed to decode header: %v", err)
@@ -28,7 +27,7 @@ func Decode(buf *bytes.Buffer, opt *types.Options) (*BGPMessage, error) {
 	}, nil
 }
 
-func decodeMsgBody(buf *bytes.Buffer, msgType uint8, l uint16, opt *types.Options) (interface{}, error) {
+func decodeMsgBody(buf *bytes.Buffer, msgType uint8, l uint16, opt *DecodeOptions) (interface{}, error) {
 	switch msgType {
 	case OpenMsg:
 		return decodeOpenMsg(buf)
@@ -42,7 +41,7 @@ func decodeMsgBody(buf *bytes.Buffer, msgType uint8, l uint16, opt *types.Option
 	return nil, fmt.Errorf("Unknown message type: %d", msgType)
 }
 
-func decodeUpdateMsg(buf *bytes.Buffer, l uint16, opt *types.Options) (*BGPUpdate, error) {
+func decodeUpdateMsg(buf *bytes.Buffer, l uint16, opt *DecodeOptions) (*BGPUpdate, error) {
 	msg := &BGPUpdate{}
 
 	err := decode(buf, []interface{}{&msg.WithdrawnRoutesLen})
diff --git a/protocols/bgp/packet/decoder_test.go b/protocols/bgp/packet/decoder_test.go
index ac611ceff133e4375e70995a2b564900671ed8aa..74e5b84f978f084c38360b85b72030fe79fe945e 100644
--- a/protocols/bgp/packet/decoder_test.go
+++ b/protocols/bgp/packet/decoder_test.go
@@ -74,7 +74,7 @@ func BenchmarkDecodeUpdateMsg(b *testing.B) {
 
 	for i := 0; i < b.N; i++ {
 		buf := bytes.NewBuffer(input)
-		_, err := decodeUpdateMsg(buf, uint16(len(input)), &types.Options{})
+		_, err := decodeUpdateMsg(buf, uint16(len(input)), &DecodeOptions{})
 		if err != nil {
 			fmt.Printf("decodeUpdateMsg failed: %v\n", err)
 		}
@@ -255,7 +255,7 @@ func TestDecode(t *testing.T) {
 
 	for _, test := range tests {
 		buf := bytes.NewBuffer(test.input)
-		msg, err := Decode(buf, &types.Options{})
+		msg, err := Decode(buf, &DecodeOptions{})
 
 		if err != nil && !test.wantFail {
 			t.Errorf("Unexpected error in test %d: %v", test.testNum, err)
@@ -1369,7 +1369,7 @@ func TestDecodeUpdateMsg(t *testing.T) {
 			if l == 0 {
 				l = uint16(len(test.input))
 			}
-			msg, err := decodeUpdateMsg(buf, l, &types.Options{})
+			msg, err := decodeUpdateMsg(buf, l, &DecodeOptions{})
 
 			if err != nil && !test.wantFail {
 				t.Fatalf("Unexpected error in test %d: %v", test.testNum, err)
@@ -1405,7 +1405,7 @@ func TestDecodeMsgBody(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		res, err := decodeMsgBody(test.buffer, test.msgType, test.length, &types.Options{})
+		res, err := decodeMsgBody(test.buffer, test.msgType, test.length, &DecodeOptions{})
 		if test.wantFail && err == nil {
 			t.Errorf("Expected error dit not happen in test %q", test.name)
 		}
diff --git a/protocols/bgp/packet/mp_reach_nlri.go b/protocols/bgp/packet/mp_reach_nlri.go
index 305ae994d1cdb383ac13a4c1455510d3cce0509d..55a709f53e96d50afae44d5894427f08c1ef7bf6 100644
--- a/protocols/bgp/packet/mp_reach_nlri.go
+++ b/protocols/bgp/packet/mp_reach_nlri.go
@@ -7,7 +7,6 @@ import (
 	"github.com/taktv6/tflow2/convert"
 
 	bnet "github.com/bio-routing/bio-rd/net"
-	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 )
 
 // MultiProtocolReachNLRI represents network layer reachability information for one prefix of an IP address family (rfc4760)
@@ -19,7 +18,7 @@ type MultiProtocolReachNLRI struct {
 	PathID   uint32
 }
 
-func (n *MultiProtocolReachNLRI) serialize(buf *bytes.Buffer, opt *types.Options) uint16 {
+func (n *MultiProtocolReachNLRI) serialize(buf *bytes.Buffer, opt *EncodeOptions) uint16 {
 	nextHop := n.NextHop.Bytes()
 
 	tempBuf := bytes.NewBuffer(nil)
@@ -29,7 +28,7 @@ func (n *MultiProtocolReachNLRI) serialize(buf *bytes.Buffer, opt *types.Options
 	tempBuf.Write(nextHop)
 	tempBuf.WriteByte(0) // RESERVED
 	for _, pfx := range n.Prefixes {
-		if opt.AddPathRX {
+		if opt.UseAddPath {
 			tempBuf.Write(convert.Uint32Byte(n.PathID))
 		}
 		tempBuf.Write(serializePrefix(pfx))
diff --git a/protocols/bgp/packet/mp_reach_nlri_test.go b/protocols/bgp/packet/mp_reach_nlri_test.go
index 73a52bba8c517f8924e65181cafcf376be3dddb0..cb6e5b544333d76f3244c8ef6895acb40783f149 100644
--- a/protocols/bgp/packet/mp_reach_nlri_test.go
+++ b/protocols/bgp/packet/mp_reach_nlri_test.go
@@ -5,7 +5,6 @@ import (
 	"testing"
 
 	bnet "github.com/bio-routing/bio-rd/net"
-	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -60,8 +59,8 @@ func TestSerializeMultiProtocolReachNLRI(t *testing.T) {
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
 			buf := &bytes.Buffer{}
-			test.nlri.serialize(buf, &types.Options{
-				AddPathRX: test.addPath,
+			test.nlri.serialize(buf, &EncodeOptions{
+				UseAddPath: test.addPath,
 			})
 			assert.Equal(t, test.expected, buf.Bytes())
 		})
diff --git a/protocols/bgp/packet/mp_unreach_nlri.go b/protocols/bgp/packet/mp_unreach_nlri.go
index 2e3475425ddb19292a6c4d5f355c8456aeac7b03..6431577ce4188837811f26bb8d819f4015c2d2a3 100644
--- a/protocols/bgp/packet/mp_unreach_nlri.go
+++ b/protocols/bgp/packet/mp_unreach_nlri.go
@@ -5,7 +5,6 @@ import (
 	"fmt"
 
 	bnet "github.com/bio-routing/bio-rd/net"
-	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -17,12 +16,12 @@ type MultiProtocolUnreachNLRI struct {
 	PathID   uint32
 }
 
-func (n *MultiProtocolUnreachNLRI) serialize(buf *bytes.Buffer, opt *types.Options) uint16 {
+func (n *MultiProtocolUnreachNLRI) serialize(buf *bytes.Buffer, opt *EncodeOptions) uint16 {
 	tempBuf := bytes.NewBuffer(nil)
 	tempBuf.Write(convert.Uint16Byte(n.AFI))
 	tempBuf.WriteByte(n.SAFI)
 	for _, pfx := range n.Prefixes {
-		if opt.AddPathRX {
+		if opt.UseAddPath {
 			tempBuf.Write(convert.Uint32Byte(n.PathID))
 		}
 		tempBuf.Write(serializePrefix(pfx))
diff --git a/protocols/bgp/packet/mp_unreach_nlri_test.go b/protocols/bgp/packet/mp_unreach_nlri_test.go
index c4484f97f71d182a8886854063368b9127154a8f..467b19e030dd208f5e1103d81465107f531591ec 100644
--- a/protocols/bgp/packet/mp_unreach_nlri_test.go
+++ b/protocols/bgp/packet/mp_unreach_nlri_test.go
@@ -5,7 +5,6 @@ import (
 	"testing"
 
 	bnet "github.com/bio-routing/bio-rd/net"
-	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -54,8 +53,8 @@ func TestSerializeMultiProtocolUnreachNLRI(t *testing.T) {
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
 			buf := &bytes.Buffer{}
-			test.nlri.serialize(buf, &types.Options{
-				AddPathRX: test.addPath,
+			test.nlri.serialize(buf, &EncodeOptions{
+				UseAddPath: test.addPath,
 			})
 			assert.Equal(t, test.expected, buf.Bytes())
 		})
diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go
index 5b5af4ecd816650ed5575dd16ede7f529fc349aa..819fc7b945d858fa30c4a34119c1c98a914dadab 100644
--- a/protocols/bgp/packet/path_attributes.go
+++ b/protocols/bgp/packet/path_attributes.go
@@ -11,7 +11,7 @@ import (
 	"github.com/taktv6/tflow2/convert"
 )
 
-func decodePathAttrs(buf *bytes.Buffer, tpal uint16, opt *types.Options) (*PathAttribute, error) {
+func decodePathAttrs(buf *bytes.Buffer, tpal uint16, opt *DecodeOptions) (*PathAttribute, error) {
 	var ret *PathAttribute
 	var eol *PathAttribute
 	var pa *PathAttribute
@@ -38,7 +38,7 @@ func decodePathAttrs(buf *bytes.Buffer, tpal uint16, opt *types.Options) (*PathA
 	return ret, nil
 }
 
-func decodePathAttr(buf *bytes.Buffer, opt *types.Options) (pa *PathAttribute, consumed uint16, err error) {
+func decodePathAttr(buf *bytes.Buffer, opt *DecodeOptions) (pa *PathAttribute, consumed uint16, err error) {
 	pa = &PathAttribute{}
 
 	err = decodePathAttrFlags(buf, pa)
@@ -66,7 +66,7 @@ func decodePathAttr(buf *bytes.Buffer, opt *types.Options) (pa *PathAttribute, c
 		}
 	case ASPathAttr:
 		asnLength := uint8(2)
-		if opt.Supports4OctetASN {
+		if opt.Use32BitASN {
 			asnLength = 4
 		}
 
@@ -445,7 +445,7 @@ func dumpNBytes(buf *bytes.Buffer, n uint16) error {
 }
 
 // Serialize serializes a path attribute
-func (pa *PathAttribute) Serialize(buf *bytes.Buffer, opt *types.Options) uint16 {
+func (pa *PathAttribute) Serialize(buf *bytes.Buffer, opt *EncodeOptions) uint16 {
 	pathAttrLen := uint16(0)
 
 	switch pa.TypeCode {
@@ -493,28 +493,28 @@ func (pa *PathAttribute) serializeOrigin(buf *bytes.Buffer) uint8 {
 	return 4
 }
 
-func (pa *PathAttribute) serializeASPath(buf *bytes.Buffer, opt *types.Options) uint8 {
+func (pa *PathAttribute) serializeASPath(buf *bytes.Buffer, opt *EncodeOptions) uint8 {
 	attrFlags := uint8(0)
 	attrFlags = setTransitive(attrFlags)
 	buf.WriteByte(attrFlags)
 	buf.WriteByte(ASPathAttr)
 
-	asnLength := uint8(2)
-	if opt.Supports4OctetASN {
-		asnLength = 4
-	}
-
 	length := uint8(0)
 	segmentsBuf := bytes.NewBuffer(nil)
 	for _, segment := range pa.Value.(types.ASPath) {
 		segmentsBuf.WriteByte(segment.Type)
 		segmentsBuf.WriteByte(uint8(len(segment.ASNs)))
 
+		asnLength := uint8(2)
+		if opt.Use32BitASN {
+			asnLength = 4
+		}
+
 		for _, asn := range segment.ASNs {
-			if asnLength == 2 {
-				segmentsBuf.Write(convert.Uint16Byte(uint16(asn)))
-			} else {
+			if opt.Use32BitASN {
 				segmentsBuf.Write(convert.Uint32Byte(asn))
+			} else {
+				segmentsBuf.Write(convert.Uint16Byte(uint16(asn)))
 			}
 		}
 		length += 2 + uint8(len(segment.ASNs))*asnLength
@@ -695,7 +695,7 @@ func (pa *PathAttribute) serializeUnknownAttribute(buf *bytes.Buffer) uint16 {
 	return uint16(len(b) + 2)
 }
 
-func (pa *PathAttribute) serializeMultiProtocolReachNLRI(buf *bytes.Buffer, opt *types.Options) uint16 {
+func (pa *PathAttribute) serializeMultiProtocolReachNLRI(buf *bytes.Buffer, opt *EncodeOptions) uint16 {
 	v := pa.Value.(MultiProtocolReachNLRI)
 	pa.Optional = true
 
@@ -705,7 +705,7 @@ func (pa *PathAttribute) serializeMultiProtocolReachNLRI(buf *bytes.Buffer, opt
 	return pa.serializeGeneric(tempBuf.Bytes(), buf)
 }
 
-func (pa *PathAttribute) serializeMultiProtocolUnreachNLRI(buf *bytes.Buffer, opt *types.Options) uint16 {
+func (pa *PathAttribute) serializeMultiProtocolUnreachNLRI(buf *bytes.Buffer, opt *EncodeOptions) uint16 {
 	v := pa.Value.(MultiProtocolUnreachNLRI)
 	pa.Optional = true
 
diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go
index dd4b31e8005812f7a8f90c36b139d8ac244e320e..e92efb76ab7194d8f4087b7cfd90cadd1be9aa4a 100644
--- a/protocols/bgp/packet/path_attributes_test.go
+++ b/protocols/bgp/packet/path_attributes_test.go
@@ -52,7 +52,7 @@ func TestDecodePathAttrs(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		res, err := decodePathAttrs(bytes.NewBuffer(test.input), uint16(len(test.input)), &types.Options{})
+		res, err := decodePathAttrs(bytes.NewBuffer(test.input), uint16(len(test.input)), &DecodeOptions{})
 
 		if test.wantFail && err == nil {
 			t.Errorf("Expected error did not happen for test %q", test.name)
@@ -249,7 +249,7 @@ func TestDecodePathAttr(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		res, _, err := decodePathAttr(bytes.NewBuffer(test.input), &types.Options{})
+		res, _, err := decodePathAttr(bytes.NewBuffer(test.input), &DecodeOptions{})
 
 		if test.wantFail && err == nil {
 			t.Errorf("Expected error did not happen for test %q", test.name)
@@ -1516,8 +1516,8 @@ func TestSerializeASPath(t *testing.T) {
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
 			buf := bytes.NewBuffer(nil)
-			opt := &types.Options{
-				Supports4OctetASN: test.use32BitASN,
+			opt := &EncodeOptions{
+				Use32BitASN: test.use32BitASN,
 			}
 			n := test.input.serializeASPath(buf, opt)
 			if n != test.expectedLen {
@@ -2020,10 +2020,7 @@ func TestSerialize(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		opt := &types.Options{
-			AddPathRX: false,
-		}
-		res, err := test.msg.SerializeUpdate(opt)
+		res, err := test.msg.SerializeUpdate(&EncodeOptions{})
 		if err != nil {
 			if test.wantFail {
 				continue
@@ -2233,8 +2230,8 @@ func TestSerializeAddPath(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		opt := &types.Options{
-			AddPathRX: true,
+		opt := &EncodeOptions{
+			UseAddPath: true,
 		}
 		res, err := test.msg.SerializeUpdate(opt)
 		if err != nil {
diff --git a/protocols/bgp/packet/update.go b/protocols/bgp/packet/update.go
index 55b0cc0b9099076edbaef35fcfab1cfc83443330..167439ab06b77d669c5de258a252b5c2105794a6 100644
--- a/protocols/bgp/packet/update.go
+++ b/protocols/bgp/packet/update.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"fmt"
 
-	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -17,14 +16,14 @@ type BGPUpdate struct {
 }
 
 // SerializeUpdate serializes an BGPUpdate to wire format
-func (b *BGPUpdate) SerializeUpdate(opt *types.Options) ([]byte, error) {
+func (b *BGPUpdate) SerializeUpdate(opt *EncodeOptions) ([]byte, error) {
 	budget := MaxLen - MinLen
 	nlriLen := 0
 	buf := bytes.NewBuffer(nil)
 
 	withdrawBuf := bytes.NewBuffer(nil)
 	for withdraw := b.WithdrawnRoutes; withdraw != nil; withdraw = withdraw.Next {
-		if opt.AddPathRX {
+		if opt.UseAddPath {
 			nlriLen = int(withdraw.serializeAddPath(withdrawBuf))
 		} else {
 			nlriLen = int(withdraw.serialize(withdrawBuf))
@@ -47,7 +46,7 @@ func (b *BGPUpdate) SerializeUpdate(opt *types.Options) ([]byte, error) {
 
 	nlriBuf := bytes.NewBuffer(nil)
 	for nlri := b.NLRI; nlri != nil; nlri = nlri.Next {
-		if opt.AddPathRX {
+		if opt.UseAddPath {
 			nlriLen = int(nlri.serializeAddPath(nlriBuf))
 		} else {
 			nlriLen = int(nlri.serialize(nlriBuf))
@@ -87,7 +86,7 @@ func (b *BGPUpdate) SerializeUpdate(opt *types.Options) ([]byte, error) {
 	return buf.Bytes(), nil
 }
 
-func (b *BGPUpdate) SerializeUpdateAddPath(opt *types.Options) ([]byte, error) {
+func (b *BGPUpdate) SerializeUpdateAddPath(opt *EncodeOptions) ([]byte, error) {
 	budget := MaxLen - MinLen
 	buf := bytes.NewBuffer(nil)
 
diff --git a/protocols/bgp/server/BUILD.bazel b/protocols/bgp/server/BUILD.bazel
index 78bdeb1f3635cabb3ead2855ae4431ee20a3c04c..bd45a72d0abd1f419175febf884094109f6eb982 100644
--- a/protocols/bgp/server/BUILD.bazel
+++ b/protocols/bgp/server/BUILD.bazel
@@ -21,7 +21,6 @@ go_library(
         "update_helper.go",
         "update_sender.go",
         "util.go",
-        "withdraw.go",
     ],
     importpath = "github.com/bio-routing/bio-rd/protocols/bgp/server",
     visibility = ["//visibility:public"],
@@ -49,7 +48,6 @@ go_test(
         "server_test.go",
         "update_helper_test.go",
         "update_sender_test.go",
-        "withdraw_test.go",
     ],
     embed = [":go_default_library"],
     deps = [
diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go
index 44437ea9ade40a7038f0fa084d5117d3dddecc1d..1cb23da4d8102e081024db968e9be8a534d4bbb7 100644
--- a/protocols/bgp/server/fsm.go
+++ b/protocols/bgp/server/fsm.go
@@ -9,7 +9,6 @@ import (
 	"time"
 
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
-	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -55,8 +54,6 @@ type FSM struct {
 	msgRecvFailCh chan error
 	stopMsgRecvCh chan struct{}
 
-	options *types.Options
-
 	local net.IP
 
 	ribsInitialized bool
@@ -64,6 +61,7 @@ type FSM struct {
 	ipv6Unicast     *fsmAddressFamily
 
 	supportsMultiProtocol bool
+	supports4OctetASN     bool
 
 	neighborID uint32
 	state      state
@@ -101,7 +99,6 @@ func newFSM2(peer *peer) *FSM {
 		msgRecvCh:        make(chan []byte),
 		msgRecvFailCh:    make(chan error),
 		stopMsgRecvCh:    make(chan struct{}),
-		options:          &types.Options{},
 	}
 
 	if peer.ipv4 != nil {
@@ -245,6 +242,12 @@ func (fsm *FSM) msgReceiver() error {
 	}
 }
 
+func (fsm *FSM) decodeOptions() *packet.DecodeOptions {
+	return &packet.DecodeOptions{
+		Use32BitASN: fsm.supports4OctetASN,
+	}
+}
+
 func (fsm *FSM) startConnectRetryTimer() {
 	fsm.connectRetryTimer = time.NewTimer(fsm.connectRetryTime)
 }
diff --git a/protocols/bgp/server/fsm_address_family.go b/protocols/bgp/server/fsm_address_family.go
index b72224a4aa0402f30e0171804801fb8dca2b0740..5426d07f3b2f0079cb382824c3ccbb8e570237fc 100644
--- a/protocols/bgp/server/fsm_address_family.go
+++ b/protocols/bgp/server/fsm_address_family.go
@@ -31,6 +31,7 @@ type fsmAddressFamily struct {
 
 	addPathSend routingtable.ClientOptions
 	addPathRecv bool
+	addPathRX   bool
 
 	initialized bool
 }
@@ -65,7 +66,7 @@ func (f *fsmAddressFamily) init(n *routingtable.Neighbor) {
 	clientOptions := routingtable.ClientOptions{
 		BestOnly: true,
 	}
-	if f.fsm.options.AddPathRX {
+	if f.addPathRX {
 		clientOptions = f.addPathSend
 	}
 	f.rib.RegisterWithOptions(f.adjRIBOut, clientOptions)
diff --git a/protocols/bgp/server/fsm_established.go b/protocols/bgp/server/fsm_established.go
index 8a090b18afa9fc06064573886677133f56460031..43986d237a6cf3509f728e648a06a56030407384 100644
--- a/protocols/bgp/server/fsm_established.go
+++ b/protocols/bgp/server/fsm_established.go
@@ -30,6 +30,8 @@ func (s establishedState) run() (state, string) {
 		}
 	}
 
+	opt := s.fsm.decodeOptions()
+
 	for {
 		select {
 		case e := <-s.fsm.eventCh:
@@ -48,7 +50,7 @@ func (s establishedState) run() (state, string) {
 		case <-s.fsm.keepaliveTimer.C:
 			return s.keepaliveTimerExpired()
 		case recvMsg := <-s.fsm.msgRecvCh:
-			return s.msgReceived(recvMsg)
+			return s.msgReceived(recvMsg, opt)
 		}
 	}
 }
@@ -74,7 +76,6 @@ func (s *establishedState) init() error {
 		LocalASN:             s.fsm.peer.localASN,
 		RouteServerClient:    s.fsm.peer.routeServerClient,
 		LocalAddress:         localAddr,
-		CapAddPathRX:         s.fsm.options.AddPathRX,
 		RouteReflectorClient: s.fsm.peer.routeReflectorClient,
 		ClusterID:            s.fsm.peer.clusterID,
 	}
@@ -148,8 +149,8 @@ func (s *establishedState) keepaliveTimerExpired() (state, string) {
 	return newEstablishedState(s.fsm), s.fsm.reason
 }
 
-func (s *establishedState) msgReceived(data []byte) (state, string) {
-	msg, err := packet.Decode(bytes.NewBuffer(data), s.fsm.options)
+func (s *establishedState) msgReceived(data []byte, opt *packet.DecodeOptions) (state, string) {
+	msg, err := packet.Decode(bytes.NewBuffer(data), opt)
 	if err != nil {
 		switch bgperr := err.(type) {
 		case packet.BGPError:
diff --git a/protocols/bgp/server/fsm_open_confirm.go b/protocols/bgp/server/fsm_open_confirm.go
index 07b8a6152dd64c56055c7cbd0745980e462c3886..17df63c1a3481b09f6b1671ce412d761e27cf240 100644
--- a/protocols/bgp/server/fsm_open_confirm.go
+++ b/protocols/bgp/server/fsm_open_confirm.go
@@ -18,6 +18,8 @@ func newOpenConfirmState(fsm *FSM) *openConfirmState {
 }
 
 func (s openConfirmState) run() (state, string) {
+	opt := s.fsm.decodeOptions()
+
 	for {
 		select {
 		case e := <-s.fsm.eventCh:
@@ -34,7 +36,7 @@ func (s openConfirmState) run() (state, string) {
 		case <-s.fsm.keepaliveTimer.C:
 			return s.keepaliveTimerExpired()
 		case recvMsg := <-s.fsm.msgRecvCh:
-			return s.msgReceived(recvMsg)
+			return s.msgReceived(recvMsg, opt)
 		}
 	}
 }
@@ -81,8 +83,8 @@ func (s *openConfirmState) keepaliveTimerExpired() (state, string) {
 	return newOpenConfirmState(s.fsm), s.fsm.reason
 }
 
-func (s *openConfirmState) msgReceived(data []byte) (state, string) {
-	msg, err := packet.Decode(bytes.NewBuffer(data), s.fsm.options)
+func (s *openConfirmState) msgReceived(data []byte, opt *packet.DecodeOptions) (state, string) {
+	msg, err := packet.Decode(bytes.NewBuffer(data), opt)
 	if err != nil {
 		switch bgperr := err.(type) {
 		case packet.BGPError:
diff --git a/protocols/bgp/server/fsm_open_sent.go b/protocols/bgp/server/fsm_open_sent.go
index 7a0999899a5d0b7089892f1fb169d3a0abdc591f..dd13dbfaa4a0f66624fc292dee97e6e5dd56abff 100644
--- a/protocols/bgp/server/fsm_open_sent.go
+++ b/protocols/bgp/server/fsm_open_sent.go
@@ -22,6 +22,9 @@ func newOpenSentState(fsm *FSM) *openSentState {
 
 func (s openSentState) run() (state, string) {
 	go s.fsm.msgReceiver()
+
+	opt := s.fsm.decodeOptions()
+
 	for {
 		select {
 		case e := <-s.fsm.eventCh:
@@ -38,7 +41,7 @@ func (s openSentState) run() (state, string) {
 		case <-s.fsm.holdTimer.C:
 			return s.holdTimerExpired()
 		case recvMsg := <-s.fsm.msgRecvCh:
-			return s.msgReceived(recvMsg)
+			return s.msgReceived(recvMsg, opt)
 		}
 	}
 }
@@ -73,8 +76,8 @@ func (s *openSentState) holdTimerExpired() (state, string) {
 	return newIdleState(s.fsm), "Holdtimer expired"
 }
 
-func (s *openSentState) msgReceived(data []byte) (state, string) {
-	msg, err := packet.Decode(bytes.NewBuffer(data), s.fsm.options)
+func (s *openSentState) msgReceived(data []byte, opt *packet.DecodeOptions) (state, string) {
+	msg, err := packet.Decode(bytes.NewBuffer(data), opt)
 	if err != nil {
 		switch bgperr := err.(type) {
 		case packet.BGPError:
@@ -191,24 +194,24 @@ func (s *openSentState) processAddPathCapability(addPathCap packet.AddPathCapabi
 	switch addPathCap.SendReceive {
 	case packet.AddPathReceive:
 		if !f.addPathSend.BestOnly {
-			s.fsm.options.AddPathRX = true
+			f.addPathRX = true
 		}
 	case packet.AddPathSend:
 		if f.addPathRecv {
-			s.fsm.options.AddPathRX = true
+			f.addPathRX = true
 		}
 	case packet.AddPathSendReceive:
 		if !f.addPathSend.BestOnly {
-			s.fsm.options.AddPathRX = true
+			f.addPathRX = true
 		}
 		if f.addPathRecv {
-			s.fsm.options.AddPathRX = true
+			f.addPathRX = true
 		}
 	}
 }
 
 func (s *openSentState) processASN4Capability(cap packet.ASN4Capability) {
-	s.fsm.options.Supports4OctetASN = true
+	s.fsm.supports4OctetASN = true
 
 	if s.peerASNRcvd == packet.ASTransASN {
 		s.peerASNRcvd = cap.ASN4
diff --git a/protocols/bgp/server/update_helper.go b/protocols/bgp/server/update_helper.go
index 2cb82934a0a12d2f25243db2bc82cd60fca10e02..a510e54e98c10e8db673b1156c26e3de1cf19f24 100644
--- a/protocols/bgp/server/update_helper.go
+++ b/protocols/bgp/server/update_helper.go
@@ -4,11 +4,12 @@ import (
 	"fmt"
 	"io"
 
-	"github.com/bio-routing/bio-rd/protocols/bgp/types"
+	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
+
 	log "github.com/sirupsen/logrus"
 )
 
-func serializeAndSendUpdate(out io.Writer, update serializeAbleUpdate, opt *types.Options) error {
+func serializeAndSendUpdate(out io.Writer, update serializeAbleUpdate, opt *packet.EncodeOptions) error {
 	updateBytes, err := update.SerializeUpdate(opt)
 	if err != nil {
 		log.Errorf("Unable to serialize BGP Update: %v", err)
@@ -23,5 +24,5 @@ func serializeAndSendUpdate(out io.Writer, update serializeAbleUpdate, opt *type
 }
 
 type serializeAbleUpdate interface {
-	SerializeUpdate(opt *types.Options) ([]byte, error)
+	SerializeUpdate(opt *packet.EncodeOptions) ([]byte, error)
 }
diff --git a/protocols/bgp/server/update_helper_test.go b/protocols/bgp/server/update_helper_test.go
index 6c599f18c965d55a9a611509ea10e2c5d5ffa35e..86a70f64d5626c4cbb38fb4eca5b793d7a548093 100644
--- a/protocols/bgp/server/update_helper_test.go
+++ b/protocols/bgp/server/update_helper_test.go
@@ -7,7 +7,6 @@ import (
 	"testing"
 
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
-	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 
 	"github.com/bio-routing/bio-rd/net"
 	"github.com/stretchr/testify/assert"
@@ -15,7 +14,7 @@ import (
 
 type failingUpdate struct{}
 
-func (f *failingUpdate) SerializeUpdate(opt *types.Options) ([]byte, error) {
+func (f *failingUpdate) SerializeUpdate(opt *packet.EncodeOptions) ([]byte, error) {
 	return nil, errors.New("general error")
 }
 
@@ -93,7 +92,7 @@ func TestSerializeAndSendUpdate(t *testing.T) {
 	}
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			opt := &types.Options{}
+			opt := &packet.EncodeOptions{}
 			err := serializeAndSendUpdate(test.buf, test.testUpdate, opt)
 			assert.Equal(t, test.err, err)
 
diff --git a/protocols/bgp/server/update_sender.go b/protocols/bgp/server/update_sender.go
index ed63c74dcbc23da9d01b7b131e2325f5278a50f8..d7e23556e603f07e98da986c28267a3d69401adc 100644
--- a/protocols/bgp/server/update_sender.go
+++ b/protocols/bgp/server/update_sender.go
@@ -20,6 +20,7 @@ type UpdateSender struct {
 	fsm       *FSM
 	afi       uint16
 	safi      uint8
+	options   *packet.EncodeOptions
 	iBGP      bool
 	rrClient  bool
 	toSendMu  sync.Mutex
@@ -33,6 +34,8 @@ type pathPfxs struct {
 }
 
 func newUpdateSender(fsm *FSM, afi uint16, safi uint8) *UpdateSender {
+	f := fsm.addressFamily(afi, safi)
+
 	return &UpdateSender{
 		fsm:       fsm,
 		afi:       afi,
@@ -41,6 +44,10 @@ func newUpdateSender(fsm *FSM, afi uint16, safi uint8) *UpdateSender {
 		rrClient:  fsm.peer.routeReflectorClient,
 		destroyCh: make(chan struct{}),
 		toSend:    make(map[string]*pathPfxs),
+		options: &packet.EncodeOptions{
+			Use32BitASN: fsm.supports4OctetASN,
+			UseAddPath:  f.addPathRX,
+		},
 	}
 }
 
@@ -108,7 +115,7 @@ func (u *UpdateSender) sender(aggrTime time.Duration) {
 			for _, pfx := range pathNLRIs.pfxs {
 				budget -= int(packet.BytesInAddr(pfx.Pfxlen())) + 1
 
-				if u.fsm.options.AddPathRX {
+				if u.options.UseAddPath {
 					budget -= 4
 				}
 
@@ -157,7 +164,7 @@ func (u *UpdateSender) sendUpdates(pathAttrs *packet.PathAttribute, updatePrefix
 			return
 		}
 
-		err = serializeAndSendUpdate(u.fsm.con, update, u.fsm.options)
+		err = serializeAndSendUpdate(u.fsm.con, update, u.options)
 		if err != nil {
 			log.Errorf("Failed to serialize and send: %v", err)
 		}
@@ -282,7 +289,7 @@ func (u *UpdateSender) withDrawPrefixes(out io.Writer, prefixes ...bnet.Prefix)
 		WithdrawnRoutes: rootNLRI,
 	}
 
-	return serializeAndSendUpdate(out, update, u.fsm.options)
+	return serializeAndSendUpdate(out, update, u.options)
 
 }
 
@@ -305,7 +312,7 @@ func (u *UpdateSender) withDrawPrefixesAddPath(out io.Writer, pfx bnet.Prefix, p
 		},
 	}
 
-	return serializeAndSendUpdate(out, update, u.fsm.options)
+	return serializeAndSendUpdate(out, update, u.options)
 }
 
 func (u *UpdateSender) withDrawPrefixesMultiProtocol(out io.Writer, pfx bnet.Prefix, p *route.Path) error {
@@ -326,7 +333,7 @@ func (u *UpdateSender) withDrawPrefixesMultiProtocol(out io.Writer, pfx bnet.Pre
 		},
 	}
 
-	return serializeAndSendUpdate(out, update, u.fsm.options)
+	return serializeAndSendUpdate(out, update, u.options)
 }
 
 // UpdateNewClient does nothing
diff --git a/protocols/bgp/server/update_sender_test.go b/protocols/bgp/server/update_sender_test.go
index d46297d6effae19b01dab67eb0bbce231916a9ae..95cb85703891f8ad3b72de17829be0d201fdf0b7 100644
--- a/protocols/bgp/server/update_sender_test.go
+++ b/protocols/bgp/server/update_sender_test.go
@@ -12,7 +12,6 @@ import (
 	"github.com/stretchr/testify/assert"
 
 	bnet "github.com/bio-routing/bio-rd/net"
-	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable/filter"
 	"github.com/bio-routing/bio-rd/routingtable/locRIB"
@@ -881,12 +880,14 @@ func TestSender(t *testing.T) {
 				importFilter: filter.NewAcceptAllFilter(),
 				exportFilter: filter.NewAcceptAllFilter(),
 			}, fsmA)
+			fsmA.ipv6Unicast.addPathRX = test.addPath
 		} else {
 			fsmA.ipv4Unicast = newFSMAddressFamily(packet.IPv4AFI, packet.UnicastSAFI, &familyParameters{
 				rib:          rib,
 				importFilter: filter.NewAcceptAllFilter(),
 				exportFilter: filter.NewAcceptAllFilter(),
 			}, fsmA)
+			fsmA.ipv4Unicast.addPathRX = test.addPath
 		}
 
 		fsmA.holdTimer = time.NewTimer(time.Second * 90)
@@ -895,12 +896,6 @@ func TestSender(t *testing.T) {
 		fsmA.state = newEstablishedState(fsmA)
 		fsmA.con = btest.NewMockConn()
 
-		if test.addPath {
-			fsmA.options = &types.Options{
-				AddPathRX: true,
-			}
-		}
-
 		updateSender := newUpdateSender(fsmA, test.afi, packet.UnicastSAFI)
 
 		for _, pathPfx := range test.paths {
@@ -990,11 +985,10 @@ func TestWithDrawPrefixes(t *testing.T) {
 		buf := bytes.NewBuffer([]byte{})
 
 		u := &UpdateSender{
-			fsm: &FSM{
-				options: &types.Options{},
-			},
-			afi:  packet.IPv6AFI,
-			safi: packet.UnicastSAFI,
+			fsm:     &FSM{},
+			afi:     packet.IPv6AFI,
+			safi:    packet.UnicastSAFI,
+			options: &packet.EncodeOptions{},
 		}
 
 		err := u.withDrawPrefixes(buf, tc.Prefix...)
@@ -1033,13 +1027,11 @@ func TestWithDrawPrefixesMultiProtocol(t *testing.T) {
 
 			u := &UpdateSender{
 				fsm: &FSM{
-					options: &types.Options{
-						AddPathRX: false,
-					},
 					supportsMultiProtocol: true,
 				},
-				afi:  packet.IPv6AFI,
-				safi: packet.UnicastSAFI,
+				afi:     packet.IPv6AFI,
+				safi:    packet.UnicastSAFI,
+				options: &packet.EncodeOptions{},
 			}
 
 			err := u.withDrawPrefixesMultiProtocol(buf, test.Prefix, &route.Path{})
@@ -1104,10 +1096,9 @@ func TestWithDrawPrefixesAddPath(t *testing.T) {
 		buf := bytes.NewBuffer([]byte{})
 
 		u := &UpdateSender{
-			fsm: &FSM{
-				options: &types.Options{
-					AddPathRX: true,
-				},
+			fsm: &FSM{},
+			options: &packet.EncodeOptions{
+				UseAddPath: true,
 			},
 		}
 
diff --git a/protocols/bgp/types/BUILD.bazel b/protocols/bgp/types/BUILD.bazel
index 5f94662087b2e46f593e4386d2bac21e65896225..50a86ef428ad5e92ffbb6365f30e566c0267873b 100644
--- a/protocols/bgp/types/BUILD.bazel
+++ b/protocols/bgp/types/BUILD.bazel
@@ -7,7 +7,6 @@ go_library(
         "as_path.go",
         "community.go",
         "large_community.go",
-        "options.go",
         "unknown_attribute.go",
     ],
     importpath = "github.com/bio-routing/bio-rd/protocols/bgp/types",
diff --git a/protocols/bgp/types/options.go b/protocols/bgp/types/options.go
deleted file mode 100644
index 19b580d2829b96d8f974311536b299211a98ca95..0000000000000000000000000000000000000000
--- a/protocols/bgp/types/options.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package types
-
-// Options represents options to the update sender, decoder and encoder
-type Options struct {
-	Supports4OctetASN bool
-	AddPathRX         bool
-}