Skip to content

Commit ccad4a2

Browse files
authored
[Tunnel] Support co-existence of IPv4 and IPv6 tunnels (#147)
Support for both IPv4 and IPv6 tunnel for default VRF. IPv6 tunnel must use Vnet-default as Vnet name and IPv4 tunnel must use Vnet-default-v4 as Vnet name. When system has both V4 and V6 tunnel decap, NON-DEFAULT VRFs always choose V6 tunnel, whereas DEFAULT VRF chose v4 tunnel if VNET name in API is provided as - Vnet-default-v4 and chose v6 tunnel if VNET name is provided as - Vnet-default When system has only one type of tunnel, all Vnets chose the configured single tunnel (IPv4 or IPv6). No change to existing behavior. Only one decap tunnel of type V4 and one decap tunnel of type V6 is permitted.
1 parent c8fa96b commit ccad4a2

File tree

4 files changed

+197
-28
lines changed

4 files changed

+197
-28
lines changed

go-server-server/go/default.go

+53-11
Original file line numberDiff line numberDiff line change
@@ -901,22 +901,31 @@ func ConfigTunnelDecapTunnelTypePost(w http.ResponseWriter, r *http.Request) {
901901
return
902902
}
903903

904-
kv, err := GetKVs(db.db_num, generateDBTableKey(db.separator, VXLAN_TUNNEL_TB, "default_vxlan_tunnel"))
904+
tunnel_name := "default_vxlan_tunnel"
905+
// Check if IP address is V4.
906+
if IsValidIP(attr.IPAddr) {
907+
tunnel_name = "default_vxlan_tunnel_v4"
908+
}
909+
910+
kv, err := GetKVs(db.db_num, generateDBTableKey(db.separator, VXLAN_TUNNEL_TB, tunnel_name))
905911
if err != nil {
906912
WriteRequestError(w, http.StatusInternalServerError, "Internal service error", []string{}, "")
907913
return
908914
}
909915

916+
//Check if tunnel already exist and the address family is same
910917
if kv != nil {
911-
WriteRequestErrorWithSubCode(w, http.StatusConflict, RESRC_EXISTS,
912-
"Object already exists: Default Vxlan VTEP", []string{}, "")
913-
return
918+
if isV4orV6(kv["src_ip"]) == isV4orV6(attr.IPAddr) {
919+
WriteRequestErrorWithSubCode(w, http.StatusConflict, RESRC_EXISTS,
920+
"Object already exists: Default Vxlan VTEP", []string{}, "")
921+
return
922+
}
914923
}
915924

916925
pt := swsscommon.NewTable(db.swss_db, VXLAN_TUNNEL_TB)
917926
defer pt.Delete()
918927

919-
pt.Set("default_vxlan_tunnel", map[string]string{
928+
pt.Set(tunnel_name, map[string]string{
920929
"src_ip": attr.IPAddr,
921930
}, "SET", "")
922931

@@ -1025,18 +1034,36 @@ func ConfigVrouterVrfIdPost(w http.ResponseWriter, r *http.Request) {
10251034
return
10261035
}
10271036

1028-
kv, err := GetKVs(db.db_num, generateDBTableKey(db.separator, VXLAN_TUNNEL_TB, "default_vxlan_tunnel"))
1037+
tunnel_name := "default_vxlan_tunnel_v4"
1038+
kv_4, err := GetKVs(db.db_num, generateDBTableKey(db.separator, VXLAN_TUNNEL_TB, tunnel_name))
10291039
if err != nil {
10301040
WriteRequestError(w, http.StatusInternalServerError, "Internal service error", []string{}, "")
10311041
return
10321042
}
10331043

1034-
if kv == nil {
1044+
tunnel_name = "default_vxlan_tunnel"
1045+
kv, err := GetKVs(db.db_num, generateDBTableKey(db.separator, VXLAN_TUNNEL_TB, tunnel_name))
1046+
if err != nil {
1047+
WriteRequestError(w, http.StatusInternalServerError, "Internal service error", []string{}, "")
1048+
return
1049+
}
1050+
1051+
if kv == nil && kv_4 == nil {
10351052
WriteRequestErrorWithSubCode(w, http.StatusConflict, DEP_MISSING,
10361053
"Default VxLAN VTEP must be created prior to creating VRF", []string{"tunnel"}, "")
10371054
return
10381055
}
10391056

1057+
var v6_tunnel, v4_tunnel bool
1058+
if kv_4 != nil {
1059+
tunnel_name = "default_vxlan_tunnel_v4"
1060+
v4_tunnel = true
1061+
}
1062+
if kv != nil {
1063+
tunnel_name = "default_vxlan_tunnel"
1064+
v6_tunnel = true
1065+
}
1066+
10401067
vnet_id := CacheGetVnetGuidId(vars["vnet_name"])
10411068
if vnet_id != 0 {
10421069
WriteRequestErrorWithSubCode(w, http.StatusConflict, RESRC_EXISTS,
@@ -1046,9 +1073,12 @@ func ConfigVrouterVrfIdPost(w http.ResponseWriter, r *http.Request) {
10461073

10471074
guid := CacheGetVniId(uint32(attr.Vnid))
10481075
if guid != "" {
1049-
WriteRequestErrorWithSubCode(w, http.StatusConflict, RESRC_EXISTS,
1050-
"Object already exists: {\"vni\":\"" + strconv.Itoa(attr.Vnid) + "\", \"vnet_name\":\"" + guid +"\"}", []string{}, "")
1051-
return
1076+
// Default Vnets can have same Vnid
1077+
if !(strings.Contains(guid, "Vnet-default")) {
1078+
WriteRequestErrorWithSubCode(w, http.StatusConflict, RESRC_EXISTS,
1079+
"Object already exists: {\"vni\":\"" + strconv.Itoa(attr.Vnid) + "\", \"vnet_name\":\"" + guid +"\"}", []string{}, "")
1080+
return
1081+
}
10521082
}
10531083

10541084
vnet_id = CacheGenAndSetVnetGuidId(vars["vnet_name"], uint32(attr.Vnid))
@@ -1070,11 +1100,23 @@ func ConfigVrouterVrfIdPost(w http.ResponseWriter, r *http.Request) {
10701100

10711101
log.Printf("debug: vnet_id_str: "+vnet_id_str)
10721102
vnetParams := make(map[string]string)
1073-
vnetParams["vxlan_tunnel"] = "default_vxlan_tunnel"
1103+
vnetParams["vxlan_tunnel"] = tunnel_name
10741104
vnetParams["vni"] = strconv.Itoa(attr.Vnid)
10751105
vnetParams["guid"] = vars["vnet_name"]
10761106
if strings.Compare(vars["vnet_name"], "Vnet-default") == 0 {
1107+
if v6_tunnel == false {
1108+
WriteRequestError(w, http.StatusInternalServerError, "Vnet-default is for V6 Tunnels, please create Vnet-default-v4", []string{}, "")
1109+
return
1110+
}
1111+
vnetParams["scope"] = "default"
1112+
vnetParams["vxlan_tunnel"] = "default_vxlan_tunnel"
1113+
} else if strings.Compare(vars["vnet_name"], "Vnet-default-v4") == 0 {
1114+
if v4_tunnel == false {
1115+
WriteRequestError(w, http.StatusInternalServerError, "V4 tunnel not created, please create V4 Vxlan Tunnel", []string{}, "")
1116+
return
1117+
}
10771118
vnetParams["scope"] = "default"
1119+
vnetParams["vxlan_tunnel"] = "default_vxlan_tunnel_v4"
10781120
}
10791121
if attr.AdvPrefix != "" {
10801122
vnetParams["advertise_prefix"] = attr.AdvPrefix

test/apitest.py

+29-6
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,24 @@ def post_generic_vxlan_tunnel(self):
213213
})
214214
self.assertEqual(rv.status_code, 204)
215215

216+
def post_generic_vxlan_v6_tunnel(self):
217+
rv = self.post_config_tunnel_decap_tunnel_type('vxlan', {
218+
'ip_addr': '2000:1000'
219+
})
220+
self.assertEqual(rv.status_code, 204)
221+
222+
def post_generic_default_vrouter_and_deps(self):
223+
self.post_generic_vxlan_tunnel()
224+
self.post_generic_vxlan_v6_tunnel()
225+
rv = self.post_config_vrouter_vrf_id("vnet-default", {
226+
'vnid': 8000
227+
})
228+
self.assertEqual(rv.status_code, 204)
229+
rv = self.post_config_vrouter_vrf_id("vnet-default-v4", {
230+
'vnid': 8000
231+
})
232+
self.assertEqual(rv.status_code, 204)
233+
216234
def post_generic_vrouter_and_deps(self):
217235
self.post_generic_vxlan_tunnel()
218236
rv = self.post_config_vrouter_vrf_id("vnet-guid-1", {
@@ -367,7 +385,7 @@ def test_post_config_tunnel_decap_tunnel_type(self):
367385
})
368386
self.assertEqual(r.status_code, 409)
369387

370-
tunnel_table = self.configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel')
388+
tunnel_table = self.configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel_v4')
371389
self.assertEqual(tunnel_table, {b'src_ip': b'34.53.1.0'})
372390
l.info("Tunnel table is %s", tunnel_table)
373391

@@ -376,7 +394,7 @@ def test_delete_config_tunnel_decap_tunnel_type(self):
376394
r = self.delete_config_tunnel_decap_tunnel_type('vxlan')
377395
self.assertEqual(r.status_code, 204)
378396
# The delete is a no-op and should return 204, moreover the tunnel should not be deleted
379-
tunnel_table = self.configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel')
397+
tunnel_table = self.configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel_v4')
380398
self.assertEqual(tunnel_table, {b'src_ip': b'34.53.1.0'})
381399

382400

@@ -406,7 +424,7 @@ def test_post_vrouter(self):
406424

407425
vrouter_table = self.configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF + '1')
408426
self.assertEqual(vrouter_table, {
409-
b'vxlan_tunnel': b'default_vxlan_tunnel',
427+
b'vxlan_tunnel': b'default_vxlan_tunnel_v4',
410428
b'vni': b'1001',
411429
b'guid': b'vnet-guid-1'
412430
})
@@ -415,6 +433,11 @@ def test_get_vrouter(self):
415433
self.post_generic_vrouter_and_deps()
416434
self.check_vrouter_exists("vnet-guid-1",1001)
417435

436+
def test_default_vrouter(self):
437+
self.post_generic_default_vrouter_and_deps()
438+
self.check_vrouter_exists("vnet-default",8000)
439+
self.check_vrouter_exists("vnet-default-v4",8000)
440+
418441
def test_duplicate_vni(self):
419442
self.post_generic_vrouter_and_deps_duplicate()
420443
self.check_vrouter_exists("vnet-guid-1",1001)
@@ -447,7 +470,7 @@ def test_vnet_name_mapping_logic(self):
447470
self.check_vrouter_exists("vnet-guid-"+str(i), 1000+i)
448471
vrouter_table = self.configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF +str(i))
449472
self.assertEqual(vrouter_table, {
450-
b'vxlan_tunnel': b'default_vxlan_tunnel',
473+
b'vxlan_tunnel': b'default_vxlan_tunnel_v4',
451474
b'vni': b'100'+str(i),
452475
b'guid': b'vnet-guid-'+str(i)
453476
})
@@ -460,7 +483,7 @@ def test_vnet_name_mapping_logic(self):
460483
self.check_vrouter_exists("vnet-guid-"+str(i+3), 1003+i)
461484
vrouter_table = self.configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF +str(i))
462485
self.assertEqual(vrouter_table, {
463-
b'vxlan_tunnel': b'default_vxlan_tunnel',
486+
b'vxlan_tunnel': b'default_vxlan_tunnel_v4',
464487
b'vni': b'100'+str(i+3),
465488
b'guid': b'vnet-guid-'+str(i+3)
466489
})
@@ -470,7 +493,7 @@ def test_vnet_name_mapping_logic(self):
470493
self.check_vrouter_exists("vnet-guid-"+str(i+6), 1006+i)
471494
vrouter_table = self.configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF +str(i+3))
472495
self.assertEqual(vrouter_table, {
473-
b'vxlan_tunnel': b'default_vxlan_tunnel',
496+
b'vxlan_tunnel': b'default_vxlan_tunnel_v4',
474497
b'vni': b'100'+str(i+6),
475498
b'guid': b'vnet-guid-'+str(i+6)
476499
})

test/restapi_client.py

+19
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,25 @@ def post_generic_vxlan_tunnel(self):
215215
})
216216
assert rv.status_code == 204
217217

218+
def post_generic_vxlan_v6_tunnel(self):
219+
rv = self.post_config_tunnel_decap_tunnel_type('vxlan', {
220+
'ip_addr': '2000::1000'
221+
})
222+
assert rv.status_code == 204
223+
224+
def post_generic_default_vrouter_and_deps(self):
225+
self.post_generic_vxlan_tunnel()
226+
self.post_generic_vxlan_v6_tunnel()
227+
rv = self.post_config_vrouter_vrf_id("Vnet-default", {
228+
'vnid': 8000
229+
})
230+
assert rv.status_code == 204
231+
232+
rv = self.post_config_vrouter_vrf_id("Vnet-default-v4", {
233+
'vnid': 8000
234+
})
235+
assert rv.status_code == 204
236+
218237
def post_generic_vrouter_and_deps(self):
219238
self.post_generic_vxlan_tunnel()
220239
rv = self.post_config_vrouter_vrf_id("vnet-guid-1", {

0 commit comments

Comments
 (0)