diff --git a/go-server-server/go/default.go b/go-server-server/go/default.go index 55a0109..3018398 100644 --- a/go-server-server/go/default.go +++ b/go-server-server/go/default.go @@ -901,22 +901,31 @@ func ConfigTunnelDecapTunnelTypePost(w http.ResponseWriter, r *http.Request) { return } - kv, err := GetKVs(db.db_num, generateDBTableKey(db.separator, VXLAN_TUNNEL_TB, "default_vxlan_tunnel")) + tunnel_name := "default_vxlan_tunnel" + // Check if IP address is V4. + if IsValidIP(attr.IPAddr) { + tunnel_name = "default_vxlan_tunnel_v4" + } + + kv, err := GetKVs(db.db_num, generateDBTableKey(db.separator, VXLAN_TUNNEL_TB, tunnel_name)) if err != nil { WriteRequestError(w, http.StatusInternalServerError, "Internal service error", []string{}, "") return } + //Check if tunnel already exist and the address family is same if kv != nil { - WriteRequestErrorWithSubCode(w, http.StatusConflict, RESRC_EXISTS, - "Object already exists: Default Vxlan VTEP", []string{}, "") - return + if isV4orV6(kv["src_ip"]) == isV4orV6(attr.IPAddr) { + WriteRequestErrorWithSubCode(w, http.StatusConflict, RESRC_EXISTS, + "Object already exists: Default Vxlan VTEP", []string{}, "") + return + } } pt := swsscommon.NewTable(db.swss_db, VXLAN_TUNNEL_TB) defer pt.Delete() - pt.Set("default_vxlan_tunnel", map[string]string{ + pt.Set(tunnel_name, map[string]string{ "src_ip": attr.IPAddr, }, "SET", "") @@ -1025,18 +1034,36 @@ func ConfigVrouterVrfIdPost(w http.ResponseWriter, r *http.Request) { return } - kv, err := GetKVs(db.db_num, generateDBTableKey(db.separator, VXLAN_TUNNEL_TB, "default_vxlan_tunnel")) + tunnel_name := "default_vxlan_tunnel_v4" + kv_4, err := GetKVs(db.db_num, generateDBTableKey(db.separator, VXLAN_TUNNEL_TB, tunnel_name)) if err != nil { WriteRequestError(w, http.StatusInternalServerError, "Internal service error", []string{}, "") return } - if kv == nil { + tunnel_name = "default_vxlan_tunnel" + kv, err := GetKVs(db.db_num, generateDBTableKey(db.separator, VXLAN_TUNNEL_TB, tunnel_name)) + if err != nil { + WriteRequestError(w, http.StatusInternalServerError, "Internal service error", []string{}, "") + return + } + + if kv == nil && kv_4 == nil { WriteRequestErrorWithSubCode(w, http.StatusConflict, DEP_MISSING, "Default VxLAN VTEP must be created prior to creating VRF", []string{"tunnel"}, "") return } + var v6_tunnel, v4_tunnel bool + if kv_4 != nil { + tunnel_name = "default_vxlan_tunnel_v4" + v4_tunnel = true + } + if kv != nil { + tunnel_name = "default_vxlan_tunnel" + v6_tunnel = true + } + vnet_id := CacheGetVnetGuidId(vars["vnet_name"]) if vnet_id != 0 { WriteRequestErrorWithSubCode(w, http.StatusConflict, RESRC_EXISTS, @@ -1046,9 +1073,12 @@ func ConfigVrouterVrfIdPost(w http.ResponseWriter, r *http.Request) { guid := CacheGetVniId(uint32(attr.Vnid)) if guid != "" { - WriteRequestErrorWithSubCode(w, http.StatusConflict, RESRC_EXISTS, - "Object already exists: {\"vni\":\"" + strconv.Itoa(attr.Vnid) + "\", \"vnet_name\":\"" + guid +"\"}", []string{}, "") - return + // Default Vnets can have same Vnid + if !(strings.Contains(guid, "Vnet-default")) { + WriteRequestErrorWithSubCode(w, http.StatusConflict, RESRC_EXISTS, + "Object already exists: {\"vni\":\"" + strconv.Itoa(attr.Vnid) + "\", \"vnet_name\":\"" + guid +"\"}", []string{}, "") + return + } } vnet_id = CacheGenAndSetVnetGuidId(vars["vnet_name"], uint32(attr.Vnid)) @@ -1070,11 +1100,23 @@ func ConfigVrouterVrfIdPost(w http.ResponseWriter, r *http.Request) { log.Printf("debug: vnet_id_str: "+vnet_id_str) vnetParams := make(map[string]string) - vnetParams["vxlan_tunnel"] = "default_vxlan_tunnel" + vnetParams["vxlan_tunnel"] = tunnel_name vnetParams["vni"] = strconv.Itoa(attr.Vnid) vnetParams["guid"] = vars["vnet_name"] if strings.Compare(vars["vnet_name"], "Vnet-default") == 0 { + if v6_tunnel == false { + WriteRequestError(w, http.StatusInternalServerError, "Vnet-default is for V6 Tunnels, please create Vnet-default-v4", []string{}, "") + return + } + vnetParams["scope"] = "default" + vnetParams["vxlan_tunnel"] = "default_vxlan_tunnel" + } else if strings.Compare(vars["vnet_name"], "Vnet-default-v4") == 0 { + if v4_tunnel == false { + WriteRequestError(w, http.StatusInternalServerError, "V4 tunnel not created, please create V4 Vxlan Tunnel", []string{}, "") + return + } vnetParams["scope"] = "default" + vnetParams["vxlan_tunnel"] = "default_vxlan_tunnel_v4" } if attr.AdvPrefix != "" { vnetParams["advertise_prefix"] = attr.AdvPrefix diff --git a/test/apitest.py b/test/apitest.py index e3c83d2..6cc5c19 100644 --- a/test/apitest.py +++ b/test/apitest.py @@ -213,6 +213,24 @@ def post_generic_vxlan_tunnel(self): }) self.assertEqual(rv.status_code, 204) + def post_generic_vxlan_v6_tunnel(self): + rv = self.post_config_tunnel_decap_tunnel_type('vxlan', { + 'ip_addr': '2000:1000' + }) + self.assertEqual(rv.status_code, 204) + + def post_generic_default_vrouter_and_deps(self): + self.post_generic_vxlan_tunnel() + self.post_generic_vxlan_v6_tunnel() + rv = self.post_config_vrouter_vrf_id("vnet-default", { + 'vnid': 8000 + }) + self.assertEqual(rv.status_code, 204) + rv = self.post_config_vrouter_vrf_id("vnet-default-v4", { + 'vnid': 8000 + }) + self.assertEqual(rv.status_code, 204) + def post_generic_vrouter_and_deps(self): self.post_generic_vxlan_tunnel() rv = self.post_config_vrouter_vrf_id("vnet-guid-1", { @@ -367,7 +385,7 @@ def test_post_config_tunnel_decap_tunnel_type(self): }) self.assertEqual(r.status_code, 409) - tunnel_table = self.configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel') + tunnel_table = self.configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel_v4') self.assertEqual(tunnel_table, {b'src_ip': b'34.53.1.0'}) l.info("Tunnel table is %s", tunnel_table) @@ -376,7 +394,7 @@ def test_delete_config_tunnel_decap_tunnel_type(self): r = self.delete_config_tunnel_decap_tunnel_type('vxlan') self.assertEqual(r.status_code, 204) # The delete is a no-op and should return 204, moreover the tunnel should not be deleted - tunnel_table = self.configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel') + tunnel_table = self.configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel_v4') self.assertEqual(tunnel_table, {b'src_ip': b'34.53.1.0'}) @@ -406,7 +424,7 @@ def test_post_vrouter(self): vrouter_table = self.configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF + '1') self.assertEqual(vrouter_table, { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'1001', b'guid': b'vnet-guid-1' }) @@ -415,6 +433,11 @@ def test_get_vrouter(self): self.post_generic_vrouter_and_deps() self.check_vrouter_exists("vnet-guid-1",1001) + def test_default_vrouter(self): + self.post_generic_default_vrouter_and_deps() + self.check_vrouter_exists("vnet-default",8000) + self.check_vrouter_exists("vnet-default-v4",8000) + def test_duplicate_vni(self): self.post_generic_vrouter_and_deps_duplicate() self.check_vrouter_exists("vnet-guid-1",1001) @@ -447,7 +470,7 @@ def test_vnet_name_mapping_logic(self): self.check_vrouter_exists("vnet-guid-"+str(i), 1000+i) vrouter_table = self.configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF +str(i)) self.assertEqual(vrouter_table, { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'100'+str(i), b'guid': b'vnet-guid-'+str(i) }) @@ -460,7 +483,7 @@ def test_vnet_name_mapping_logic(self): self.check_vrouter_exists("vnet-guid-"+str(i+3), 1003+i) vrouter_table = self.configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF +str(i)) self.assertEqual(vrouter_table, { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'100'+str(i+3), b'guid': b'vnet-guid-'+str(i+3) }) @@ -470,7 +493,7 @@ def test_vnet_name_mapping_logic(self): self.check_vrouter_exists("vnet-guid-"+str(i+6), 1006+i) vrouter_table = self.configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF +str(i+3)) self.assertEqual(vrouter_table, { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'100'+str(i+6), b'guid': b'vnet-guid-'+str(i+6) }) diff --git a/test/restapi_client.py b/test/restapi_client.py index c8cdf90..07ed6e1 100644 --- a/test/restapi_client.py +++ b/test/restapi_client.py @@ -215,6 +215,25 @@ def post_generic_vxlan_tunnel(self): }) assert rv.status_code == 204 + def post_generic_vxlan_v6_tunnel(self): + rv = self.post_config_tunnel_decap_tunnel_type('vxlan', { + 'ip_addr': '2000::1000' + }) + assert rv.status_code == 204 + + def post_generic_default_vrouter_and_deps(self): + self.post_generic_vxlan_tunnel() + self.post_generic_vxlan_v6_tunnel() + rv = self.post_config_vrouter_vrf_id("Vnet-default", { + 'vnid': 8000 + }) + assert rv.status_code == 204 + + rv = self.post_config_vrouter_vrf_id("Vnet-default-v4", { + 'vnid': 8000 + }) + assert rv.status_code == 204 + def post_generic_vrouter_and_deps(self): self.post_generic_vxlan_tunnel() rv = self.post_config_vrouter_vrf_id("vnet-guid-1", { diff --git a/test/test_restapi.py b/test/test_restapi.py index e11a5bc..bea6af8 100644 --- a/test/test_restapi.py +++ b/test/test_restapi.py @@ -119,17 +119,32 @@ def test_post_config_tunnel_decap_tunnel_type(self, setup_restapi_client): }) assert r.status_code == 409 - tunnel_table = configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel') + tunnel_table = configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel_v4') assert tunnel_table == {b'src_ip': b'34.53.1.0'} logging.info("Tunnel table is %s", tunnel_table) + # Test V6 tunnel + r = restapi_client.post_config_tunnel_decap_tunnel_type('vxlan', { + 'ip_addr': '2000::1000' + }) + assert r.status_code == 204 + + r = restapi_client.post_config_tunnel_decap_tunnel_type('vxlan', { + 'ip_addr': '2000::1001' + }) + assert r.status_code == 409 + + tunnel_table = configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel') + assert tunnel_table == {b'src_ip': b'2000::1000'} + logging.info("Tunnel v6 table is %s", tunnel_table) + def test_delete_config_tunnel_decap_tunnel_type(self, setup_restapi_client): _, _, configdb, restapi_client = setup_restapi_client restapi_client.post_generic_vxlan_tunnel() r = restapi_client.delete_config_tunnel_decap_tunnel_type('vxlan') assert r.status_code == 204 # The delete is a no-op and should return 204, moreover the tunnel should not be deleted - tunnel_table = configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel') + tunnel_table = configdb.hgetall(VXLAN_TUNNEL_TB + '|default_vxlan_tunnel_v4') assert tunnel_table == {b'src_ip': b'34.53.1.0'} @@ -163,7 +178,7 @@ def test_post_vrouter(self, setup_restapi_client): vrouter_table = configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF + '1') assert vrouter_table == { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'1001', b'guid': b'vnet-guid-1' } @@ -178,7 +193,7 @@ def test_post_vrouter_duplicate(self, setup_restapi_client): vrouter_table = configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF + '1') assert vrouter_table == { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'1001', b'guid': b'vnet-guid-1' } @@ -200,7 +215,7 @@ def test_post_vrouter_with_advertise_prefix(self, setup_restapi_client): vrouter_table = configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF + '1') assert vrouter_table == { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'1001', b'guid': b'vnet-guid-1', b'advertise_prefix': b'false' @@ -213,7 +228,7 @@ def test_post_vrouter_with_advertise_prefix(self, setup_restapi_client): vrouter_table = configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF + '2') assert vrouter_table == { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'1002', b'guid': b'vnet-guid-2', b'advertise_prefix': b'true' @@ -231,7 +246,7 @@ def test_post_vrouter_with_overlay_dmac(self, setup_restapi_client): vrouter_table = configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF + '1') assert vrouter_table == { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'1001', b'guid': b'vnet-guid-1', b'advertise_prefix': b'true', @@ -241,6 +256,22 @@ def test_post_vrouter_with_overlay_dmac(self, setup_restapi_client): def test_post_vrouter_default(self, setup_restapi_client): _, _, configdb, restapi_client = setup_restapi_client restapi_client.post_generic_vxlan_tunnel() + r = restapi_client.post_config_vrouter_vrf_id("Vnet-default-v4", { + 'vnid': 2001 + }) + assert r.status_code == 204 + + vrouter_table = configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF + '1') + assert vrouter_table == { + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', + b'vni': b'2001', + b'guid': b'Vnet-default-v4', + b'scope': b'default' + } + + def test_post_vrouter_v6_default(self, setup_restapi_client): + _, _, configdb, restapi_client = setup_restapi_client + restapi_client.post_generic_vxlan_v6_tunnel() r = restapi_client.post_config_vrouter_vrf_id("Vnet-default", { 'vnid': 2001 }) @@ -252,13 +283,49 @@ def test_post_vrouter_default(self, setup_restapi_client): b'vni': b'2001', b'guid': b'Vnet-default', b'scope': b'default' - } + } + + def test_post_vrouter_v4_v6_default(self, setup_restapi_client): + _, _, configdb, restapi_client = setup_restapi_client + restapi_client.post_generic_vxlan_tunnel() + restapi_client.post_generic_vxlan_v6_tunnel() + r = restapi_client.post_config_vrouter_vrf_id("Vnet-default", { + 'vnid': 2001 + }) + assert r.status_code == 204 + + vrouter_table = configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF + '1') + assert vrouter_table == { + b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vni': b'2001', + b'guid': b'Vnet-default', + b'scope': b'default' + } + + r = restapi_client.post_config_vrouter_vrf_id("Vnet-default-v4", { + 'vnid': 2001 + }) + assert r.status_code == 204 + + vrouter_table = configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF + '2') + assert vrouter_table == { + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', + b'vni': b'2001', + b'guid': b'Vnet-default-v4', + b'scope': b'default' + } def test_get_vrouter(self, setup_restapi_client): _, _, _, restapi_client = setup_restapi_client restapi_client.post_generic_vrouter_and_deps() self.check_vrouter_exists(restapi_client, "vnet-guid-1",1001) + def test_default_vrouter(self, setup_restapi_client): + _, _, _, restapi_client = setup_restapi_client + restapi_client.post_generic_default_vrouter_and_deps() + self.check_vrouter_exists(restapi_client,"Vnet-default",8000) + self.check_vrouter_exists(restapi_client,"Vnet-default-v4",8000) + def test_duplicate_vni(self, setup_restapi_client): _, _, _, restapi_client = setup_restapi_client restapi_client.post_generic_vrouter_and_deps_duplicate() @@ -295,7 +362,7 @@ def test_vnet_name_mapping_logic(self, setup_restapi_client): self.check_vrouter_exists(restapi_client, "vnet-guid-"+str(i), 1000+i) vrouter_table = configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF +str(i)) assert vrouter_table == { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'100'+str(i).encode(), b'guid': b'vnet-guid-'+str(i).encode() } @@ -308,7 +375,7 @@ def test_vnet_name_mapping_logic(self, setup_restapi_client): self.check_vrouter_exists(restapi_client, "vnet-guid-"+str(i+3), 1003+i) vrouter_table = configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF +str(i)) assert vrouter_table == { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'100'+str(i+3).encode(), b'guid': b'vnet-guid-'+str(i+3).encode() } @@ -318,7 +385,7 @@ def test_vnet_name_mapping_logic(self, setup_restapi_client): self.check_vrouter_exists(restapi_client, "vnet-guid-"+str(i+6), 1006+i) vrouter_table = configdb.hgetall(VNET_TB + '|' + VNET_NAME_PREF +str(i+3)) assert vrouter_table == { - b'vxlan_tunnel': b'default_vxlan_tunnel', + b'vxlan_tunnel': b'default_vxlan_tunnel_v4', b'vni': b'100'+str(i+6).encode(), b'guid': b'vnet-guid-'+str(i+6).encode() } @@ -1895,6 +1962,24 @@ def test_post_vrouter_with_advertise_prefix(self, setup_restapi_client): }) assert r.status_code == 400 + def test_post_vrouter_v4_default(self, setup_restapi_client): + _, _, configdb, restapi_client = setup_restapi_client + #Create V4 only tunnel + restapi_client.post_generic_vxlan_tunnel() + r = restapi_client.post_config_vrouter_vrf_id("Vnet-default", { + 'vnid': 2001 + }) + assert r.status_code == 500 + + def test_post_vrouter_v6_default(self, setup_restapi_client): + _, _, configdb, restapi_client = setup_restapi_client + #Create V6 only tunnel + restapi_client.post_generic_vxlan_v6_tunnel() + r = restapi_client.post_config_vrouter_vrf_id("Vnet-default-v4", { + 'vnid': 2001 + }) + assert r.status_code == 500 + # Vlan def test_post_vlan_which_exists(self, setup_restapi_client): _, _, _, restapi_client = setup_restapi_client