diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go
index 1527f8cf6e7d3d3ff9365068272aa3fad52e41d0..248b731714389096a62e2381a548780beb8318e7 100644
--- a/protocols/bgp/packet/path_attributes_test.go
+++ b/protocols/bgp/packet/path_attributes_test.go
@@ -1580,6 +1580,212 @@ func TestSerialize(t *testing.T) {
 	}
 }
 
+func TestSerializeAddPath(t *testing.T) {
+	tests := []struct {
+		name     string
+		msg      *BGPUpdateAddPath
+		expected []byte
+		wantFail bool
+	}{
+		{
+			name: "Withdraw only",
+			msg: &BGPUpdateAddPath{
+				WithdrawnRoutes: &NLRIAddPath{
+					PathIdentifier: 257,
+					IP:             strAddr("100.110.120.0"),
+					Pfxlen:         24,
+				},
+			},
+			expected: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				0, 31, // Length
+				2,    // Msg Type
+				0, 8, // Withdrawn Routes Length
+				0, 0, 1, 1, // Path Identifier
+				24, 100, 110, 120, // NLRI
+				0, 0, // Total Path Attribute Length
+			},
+		},
+		{
+			name: "NLRI only",
+			msg: &BGPUpdateAddPath{
+				NLRI: &NLRIAddPath{
+					PathIdentifier: 257,
+					IP:             strAddr("100.110.128.0"),
+					Pfxlen:         17,
+				},
+			},
+			expected: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				0, 31, // Length
+				2,    // Msg Type
+				0, 0, // Withdrawn Routes Length
+				0, 0, // Total Path Attribute Length
+				0, 0, 1, 1, // Path Identifier
+				17, 100, 110, 128, // NLRI
+			},
+		},
+		{
+			name: "Path Attributes only",
+			msg: &BGPUpdateAddPath{
+				PathAttributes: &PathAttribute{
+					Optional:   true,
+					Transitive: true,
+					TypeCode:   OriginAttr,
+					Value:      uint8(0), // IGP
+				},
+			},
+			expected: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				0, 27, // Length
+				2,    // Msg Type
+				0, 0, // Withdrawn Routes Length
+				0, 4, // Total Path Attribute Length
+				64, // Attr. Flags
+				1,  // Attr. Type Code
+				1,  // Length
+				0,  // Value
+			},
+		},
+		{
+			name: "Full test",
+			msg: &BGPUpdateAddPath{
+				WithdrawnRoutes: &NLRIAddPath{
+					IP:     strAddr("10.0.0.0"),
+					Pfxlen: 8,
+					Next: &NLRIAddPath{
+						IP:     strAddr("192.168.0.0"),
+						Pfxlen: 16,
+					},
+				},
+				PathAttributes: &PathAttribute{
+					TypeCode: OriginAttr,
+					Value:    uint8(0),
+					Next: &PathAttribute{
+						TypeCode: ASPathAttr,
+						Value: ASPath{
+							{
+								Type: 2,
+								ASNs: []uint32{100, 155, 200},
+							},
+							{
+								Type: 1,
+								ASNs: []uint32{10, 20},
+							},
+						},
+						Next: &PathAttribute{
+							TypeCode: NextHopAttr,
+							Value:    strAddr("10.20.30.40"),
+							Next: &PathAttribute{
+								TypeCode: MEDAttr,
+								Value:    uint32(100),
+								Next: &PathAttribute{
+									TypeCode: LocalPrefAttr,
+									Value:    uint32(500),
+									Next: &PathAttribute{
+										TypeCode: AtomicAggrAttr,
+										Next: &PathAttribute{
+											TypeCode: AggregatorAttr,
+											Value:    uint16(200),
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+				NLRI: &NLRIAddPath{
+					IP:     strAddr("8.8.8.0"),
+					Pfxlen: 24,
+					Next: &NLRIAddPath{
+						IP:     strAddr("185.65.240.0"),
+						Pfxlen: 22,
+					},
+				},
+			},
+			expected: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				0, 102, // Length
+				2, // Msg Type
+
+				// Withdraws
+				0, 13, // Withdrawn Routes Length
+				0, 0, 0, 0, // Path Identifier
+				8, 10, // Withdraw 10/8
+				0, 0, 0, 0, // Path Identifier
+				16, 192, 168, // Withdraw 192.168/16
+
+				0, 50, // Total Path Attribute Length
+
+				// ORIGIN
+				64, // Attr. Flags
+				1,  // Attr. Type Code
+				1,  // Length
+				0,  // Value
+				// ASPath
+				64,                     // Attr. Flags
+				2,                      // Attr. Type Code
+				14,                     // Attr. Length
+				2,                      // Path Segment Type = AS_SEQUENCE
+				3,                      // Path Segment Length
+				0, 100, 0, 155, 0, 200, // ASNs
+				1,            // Path Segment Type = AS_SET
+				2,            // Path Segment Type = AS_SET
+				0, 10, 0, 20, // ASNs
+				// Next Hop
+				64,             // Attr. Flags
+				3,              // Attr. Type Code
+				4,              // Length
+				10, 20, 30, 40, // Next Hop Address
+				// MED
+				128,          // Attr. Flags
+				4,            // Attr Type Code
+				4,            // Length
+				0, 0, 0, 100, // MED = 100
+				// LocalPref
+				64,           // Attr. Flags
+				5,            // Attr. Type Code
+				4,            // Length
+				0, 0, 1, 244, // Localpref
+				// Atomic Aggregate
+				64, // Attr. Flags
+				6,  // Attr. Type Code
+				0,  // Length
+				// Aggregator
+				192,    // Attr. Flags
+				7,      // Attr. Type Code
+				2,      // Length
+				0, 200, // Aggregator ASN = 200
+
+				// NLRI
+				0, 0, 0, 0, // Path Identifier
+				24, 8, 8, 8, // 8.8.8.0/24
+				0, 0, 0, 0, // Path Identifier
+				22, 185, 65, 240, // 185.65.240.0/22
+			},
+		},
+	}
+
+	for _, test := range tests {
+		res, err := test.msg.SerializeUpdate()
+		if err != nil {
+			if test.wantFail {
+				continue
+			}
+
+			t.Errorf("Unexpected failure for test %q: %v", test.name, err)
+			continue
+		}
+
+		if test.wantFail {
+			t.Errorf("Unexpected success for test %q", test.name)
+			continue
+		}
+
+		assert.Equalf(t, test.expected, res, "%s", test.name)
+	}
+}
+
 func TestParseASPathStr(t *testing.T) {
 	tests := []struct {
 		name     string
diff --git a/routingtable/table_test.go b/routingtable/table_test.go
index a2eb10f76f93046fe71e98e59998ff52e15283b5..ef18c5175533a649504f4d6ade2a43edcda102ff 100644
--- a/routingtable/table_test.go
+++ b/routingtable/table_test.go
@@ -262,6 +262,12 @@ func TestGetLonger(t *testing.T) {
 				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 12), nil),
 			},
 		},
+		{
+			name:     "Test 2: Empty root",
+			routes:   nil,
+			needle:   net.NewPfx(strAddr("10.0.0.0"), 8),
+			expected: []*route.Route{},
+		},
 	}
 
 	for _, test := range tests {
@@ -445,6 +451,372 @@ func TestRemovePath(t *testing.T) {
 	}
 }
 
+func TestReplacePath(t *testing.T) {
+	tests := []struct {
+		name        string
+		routes      []*route.Route
+		replacePfx  net.Prefix
+		replacePath *route.Path
+		expected    []*route.Route
+		expectedOld []*route.Path
+	}{
+		{
+			name:       "replace in empty table",
+			replacePfx: net.NewPfx(strAddr("10.0.0.0"), 8),
+			replacePath: &route.Path{
+				Type:    route.BGPPathType,
+				BGPPath: &route.BGPPath{},
+			},
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type:    route.BGPPathType,
+					BGPPath: &route.BGPPath{},
+				}),
+			},
+			expectedOld: nil,
+		},
+		{
+			name: "replace not existing prefix with multiple paths",
+			routes: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1001,
+						NextHop:   101,
+					},
+				}),
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			replacePfx: net.NewPfx(strAddr("10.0.0.0"), 8),
+			replacePath: &route.Path{
+				Type: route.BGPPathType,
+				BGPPath: &route.BGPPath{
+					LocalPref: 1000,
+				},
+			},
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1000,
+					},
+				}),
+				newMultiPathRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1001,
+						NextHop:   101,
+					},
+				}, &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			expectedOld: []*route.Path{},
+		},
+		{
+			name: "replace existing prefix with multiple paths",
+			routes: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1,
+					},
+				}),
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 2,
+					},
+				}),
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1001,
+						NextHop:   101,
+					},
+				}),
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			replacePfx: net.NewPfx(strAddr("10.0.0.0"), 8),
+			replacePath: &route.Path{
+				Type: route.BGPPathType,
+				BGPPath: &route.BGPPath{
+					LocalPref: 1000,
+				},
+			},
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1000,
+					},
+				}),
+				newMultiPathRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1001,
+						NextHop:   101,
+					},
+				}, &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			expectedOld: []*route.Path{
+				{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1,
+					},
+				},
+				{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 2,
+					},
+				},
+			},
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			rt := NewRoutingTable()
+			for _, route := range test.routes {
+				for _, p := range route.Paths() {
+					rt.AddPath(route.Prefix(), p)
+				}
+			}
+
+			old := rt.ReplacePath(test.replacePfx, test.replacePath)
+			assert.ElementsMatch(t, test.expectedOld, old)
+			assert.ElementsMatch(t, test.expected, rt.Dump())
+		})
+
+	}
+}
+
+func TestRemovePrefix(t *testing.T) {
+	tests := []struct {
+		name        string
+		routes      []*route.Route
+		removePfx   net.Prefix
+		expected    []*route.Route
+		expectedOld []*route.Path
+	}{
+		{
+			name:        "remove in empty table",
+			removePfx:   net.NewPfx(strAddr("10.0.0.0"), 8),
+			expected:    []*route.Route{},
+			expectedOld: nil,
+		},
+		{
+			name: "remove not exist prefix",
+			routes: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1,
+					},
+				}),
+
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			removePfx: net.NewPfx(strAddr("12.0.0.0"), 8),
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1,
+					},
+				}),
+
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			expectedOld: nil,
+		},
+		{
+			name: "remove not existing more specific prefix",
+			routes: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1,
+					},
+				}),
+
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			removePfx: net.NewPfx(strAddr("10.0.0.0"), 9),
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1,
+					},
+				}),
+
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			expectedOld: nil,
+		},
+		{
+			name: "remove not existing more less prefix",
+			routes: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1,
+					},
+				}),
+
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			removePfx: net.NewPfx(strAddr("10.0.0.0"), 7),
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1,
+					},
+				}),
+
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			expectedOld: nil,
+		},
+		{
+			name: "remove existing prefix",
+			routes: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1,
+					},
+				}),
+				route.NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 2,
+					},
+				}),
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			removePfx: net.NewPfx(strAddr("10.0.0.0"), 8),
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(strAddr("11.0.0.0"), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1002,
+						NextHop:   100,
+					},
+				}),
+			},
+			expectedOld: []*route.Path{
+				{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 1,
+					},
+				},
+				{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref: 2,
+					},
+				},
+			},
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			rt := NewRoutingTable()
+			for _, route := range test.routes {
+				for _, p := range route.Paths() {
+					rt.AddPath(route.Prefix(), p)
+				}
+			}
+
+			old := rt.RemovePfx(test.removePfx)
+			assert.ElementsMatch(t, test.expectedOld, old)
+			assert.ElementsMatch(t, test.expected, rt.Dump())
+		})
+
+	}
+}
+
+func newMultiPathRoute(pfx net.Prefix, paths ...*route.Path) *route.Route {
+	if len(paths) == 0 {
+		return route.NewRoute(pfx, nil)
+	}
+	r := route.NewRoute(pfx, paths[0])
+	for i := 1; i < len(paths); i++ {
+		r.AddPath(paths[i])
+	}
+	return r
+
+}
+
 func strAddr(s string) uint32 {
 	ret, _ := net.StrToAddr(s)
 	return ret