diff --git a/doc/IPset.md b/doc/IPset.md index 06a36b5e2..e5f4645db 100644 --- a/doc/IPset.md +++ b/doc/IPset.md @@ -459,7 +459,7 @@ bin/dpip: invalid parameter The hash:ip,port,net set type uses a hash table to store IP address, port number and IP network address triples. Both IPv4 and IPv6 address are supported. The IP address of the IP and net should be of the same family. When adding/deleting entries, ranges are allowed but is transformed to specific host IP and port entries when stored into hash table for the "ip" and "port" segments. IPv4 supports both IP range and IP CIDR, while IPv6 supports IP CIDR only. Network address with zero prefix size is not supported, and is interpreted as host prefix size, i.e., 32 for IPv4 and 128 for IPv6. Option "nomatch" can be used to set exceptions to the set when add/deleting entries. If a test is matched against with a "nomatch" entry, then the result would end with false. The port number is interpreted together with a protocol. Supported protocols include TCP, UDP, ICMP, and ICMPv6, any other protocols are interpreted as unspec type with a protocol number of zero. ```bash -# ./bin/dpip ipset create bar hash:ip,port,net +# ./bin/dpip ipset -6 create bar hash:ip,port,net # ./bin/dpip ipset add bar 2001::1,8080-8082,2002::/64 # ./bin/dpip ipset add bar 2001::1,8080-8082,2002::aaaa:bbbb:ccc0:0/108 nomatch # ./bin/dpip ipset -v list bar diff --git a/include/conf/blklst.h b/include/conf/blklst.h index 2b2c9a044..84d7be271 100644 --- a/include/conf/blklst.h +++ b/include/conf/blklst.h @@ -24,6 +24,7 @@ #include "inet.h" #include "conf/sockopts.h" +#include "conf/ipset.h" struct dp_vs_blklst_entry { union inet_addr addr; @@ -31,15 +32,14 @@ struct dp_vs_blklst_entry { typedef struct dp_vs_blklst_conf { /* identify service */ - union inet_addr blklst; union inet_addr vaddr; - int af; - uint32_t fwmark; uint16_t vport; uint8_t proto; - uint8_t padding; + uint8_t af; - /* for set */ + /* subject and ipset are mutual exclusive */ + union inet_addr subject; + char ipset[IPSET_MAXNAMELEN]; } dpvs_blklst_t; struct dp_vs_blklst_conf_array { diff --git a/include/conf/ipset.h b/include/conf/ipset.h index 7a080a226..1e59cc66c 100644 --- a/include/conf/ipset.h +++ b/include/conf/ipset.h @@ -32,7 +32,7 @@ #define IPSET_F_FORCE 0x0001 enum ipset_op { - IPSET_OP_ADD, + IPSET_OP_ADD = 1, IPSET_OP_DEL, IPSET_OP_TEST, IPSET_OP_CREATE, @@ -43,34 +43,36 @@ enum ipset_op { }; struct ipset_option { - int family; union { struct { - bool comment; - int hashsize; - int maxelem; - } create; + int32_t hashsize; + uint32_t maxelem; + uint8_t comment; + } __attribute__((__packed__)) create; struct { - bool nomatch; - } add; + char padding[8]; + uint8_t nomatch; + } __attribute__((__packed__)) add; }; -}; + uint8_t family; +} __attribute__((__packed__)); struct ipset_param { char type[IPSET_MAXNAMELEN]; char name[IPSET_MAXNAMELEN]; char comment[IPSET_MAXCOMLEN]; - int opcode; - struct ipset_option option; + uint16_t opcode; uint16_t flag; + struct ipset_option option; uint8_t proto; uint8_t cidr; struct inet_addr_range range; /* port in host byteorder */ - uint8_t mac[6]; char iface[IFNAMSIZ]; + uint8_t mac[6]; /* for type with 2 nets */ + uint8_t padding; uint8_t cidr2; struct inet_addr_range range2; //uint8_t mac[2]; @@ -83,43 +85,48 @@ struct ipset_member { uint8_t cidr; uint8_t proto; uint16_t port; - uint8_t mac[6]; char iface[IFNAMSIZ]; - bool nomatch; + uint8_t mac[6]; + uint8_t nomatch; /* second net */ - union inet_addr addr2; uint8_t cidr2; uint16_t port2; + uint8_t padding[2]; + union inet_addr addr2; }; struct ipset_info { char name[IPSET_MAXNAMELEN]; char type[IPSET_MAXNAMELEN]; - bool comment; + uint8_t comment; + + uint8_t af; + uint8_t padding[2]; union { struct ipset_bitmap_header { - struct inet_addr_range range; uint8_t cidr; + uint8_t padding[3]; + struct inet_addr_range range; } bitmap; struct ipset_hash_header { - int hashsize; - int maxelem; + uint8_t padding[4]; // aligned for dpvs-agent + int32_t hashsize; + uint32_t maxelem; } hash; }; - int af; - size_t size; - int entries; - int references; + uint32_t size; + uint32_t entries; + uint32_t references; void *members; }; struct ipset_info_array { - int nipset; - struct ipset_info infos[0]; + uint32_t nipset; + struct ipset_info infos[0]; } __attribute__((__packed__)); #endif /* __DPVS_IPSET_CONF_H__ */ diff --git a/include/conf/whtlst.h b/include/conf/whtlst.h index 8da9f4d57..4edc8880b 100644 --- a/include/conf/whtlst.h +++ b/include/conf/whtlst.h @@ -23,21 +23,22 @@ #define __DPVS_WHTLST_CONF_H__ #include "inet.h" #include "conf/sockopts.h" +#include "conf/ipset.h" + struct dp_vs_whtlst_entry { union inet_addr addr; }; typedef struct dp_vs_whtlst_conf { /* identify service */ - union inet_addr whtlst; union inet_addr vaddr; - int af; - uint32_t fwmark; uint16_t vport; uint8_t proto; - uint8_t padding; + uint8_t af; - /* for set */ + /* subject and ipset are mutual exclusive */ + union inet_addr subject; + char ipset[IPSET_MAXNAMELEN]; } dpvs_whtlst_t; struct dp_vs_whtlst_conf_array { diff --git a/include/ipset/ipset.h b/include/ipset/ipset.h index 68ded707a..6c1d3649a 100644 --- a/include/ipset/ipset.h +++ b/include/ipset/ipset.h @@ -30,7 +30,7 @@ #define IPSET #define RTE_LOGTYPE_IPSET RTE_LOGTYPE_USER1 -#define IPSET_ADT_MAX 3 +#define IPSET_ADT_MAX IPSET_OP_MAX struct ipset; diff --git a/include/ipvs/blklst.h b/include/ipvs/blklst.h index d3326be93..bb9b0cd06 100644 --- a/include/ipvs/blklst.h +++ b/include/ipvs/blklst.h @@ -18,20 +18,25 @@ #ifndef __DPVS_BLKLST_H__ #define __DPVS_BLKLST_H__ #include "conf/common.h" -#include "ipvs/service.h" #include "timer.h" +#include "ipvs/service.h" +#include "ipset/ipset.h" struct blklst_entry { struct list_head list; - int af; - uint8_t proto; - uint16_t vport; + union inet_addr vaddr; - union inet_addr blklst; + uint16_t vport; + uint8_t proto; + uint8_t af; + + union inet_addr subject; + struct ipset *set; + bool dst_match; /* internal use for ipset */ }; -struct blklst_entry *dp_vs_blklst_lookup(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *blklst); +bool dp_vs_blklst_filtered(int af, uint8_t proto, const union inet_addr *vaddr, + uint16_t vport, const union inet_addr *subject, struct rte_mbuf *mbuf); void dp_vs_blklst_flush(struct dp_vs_service *svc); int dp_vs_blklst_init(void); diff --git a/include/ipvs/whtlst.h b/include/ipvs/whtlst.h index 2288d5f96..d447bc5cc 100644 --- a/include/ipvs/whtlst.h +++ b/include/ipvs/whtlst.h @@ -19,20 +19,23 @@ #define __DPVS_WHTLST_H__ #include "conf/common.h" #include "ipvs/service.h" +#include "ipset/ipset.h" struct whtlst_entry { struct list_head list; - int af; + union inet_addr vaddr; uint16_t vport; uint8_t proto; - union inet_addr whtlst; + uint8_t af; + + union inet_addr subject; + struct ipset *set; + bool dst_match; /* internal use of ipset */ }; -struct whtlst_entry *dp_vs_whtlst_lookup(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *whtlst); -bool dp_vs_whtlst_allow(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *whtlst); +bool dp_vs_whtlst_filtered(int af, uint8_t proto, const union inet_addr *vaddr, + uint16_t vport, const union inet_addr *subject, struct rte_mbuf *mbuf); void dp_vs_whtlst_flush(struct dp_vs_service *svc); int dp_vs_whtlst_init(void); diff --git a/src/ipset/ipset_bitmap.c b/src/ipset/ipset_bitmap.c index eaa6d376e..63a554635 100644 --- a/src/ipset/ipset_bitmap.c +++ b/src/ipset/ipset_bitmap.c @@ -32,7 +32,7 @@ bitmap_add(struct ipset *set, void *value, uint16_t flag) /* To avoid same IP, different MAC or other elements */ if (ret || test_bit(e->id, map->members)) { - if (flag & IPSET_F_FORCE) + if (flag & IPSET_F_FORCE) return EDPVS_OK; return EDPVS_EXIST; } @@ -51,8 +51,11 @@ bitmap_del(struct ipset *set, void *value, uint16_t flag) if (e->id >= map->elements) return EDPVS_INVAL; - if (!do(del, value, map)) + if (!do(del, value, map)) { + if (flag & IPSET_F_FORCE) + return EDPVS_OK; return EDPVS_NOTEXIST; + } set->elements--; return EDPVS_OK; @@ -70,7 +73,11 @@ bitmap_test(struct ipset *set, void *value, uint16_t flag) return do(test, value, map, set->dsize); } -ipset_adtfn bitmap_adtfn[IPSET_ADT_MAX] = { bitmap_add, bitmap_del, bitmap_test }; +ipset_adtfn bitmap_adtfn[IPSET_ADT_MAX] = { + [ IPSET_OP_ADD ] = bitmap_add, + [ IPSET_OP_DEL ] = bitmap_del, + [ IPSET_OP_TEST ] = bitmap_test +}; void bitmap_flush(struct ipset *set) diff --git a/src/ipset/ipset_hash.c b/src/ipset/ipset_hash.c index e4b93e18f..07c35eaad 100644 --- a/src/ipset/ipset_hash.c +++ b/src/ipset/ipset_hash.c @@ -160,6 +160,8 @@ hash_del(struct ipset *set, void *value, uint16_t flag) return EDPVS_OK; } } + if (flag & IPSET_F_FORCE) + return EDPVS_OK; return EDPVS_NOTEXIST; } @@ -245,7 +247,11 @@ hash_test(struct ipset *set, void *value, uint16_t flag) return 0; } -ipset_adtfn hash_adtfn[IPSET_ADT_MAX] = { hash_add, hash_del, hash_test }; +ipset_adtfn hash_adtfn[IPSET_ADT_MAX] = { + [ IPSET_OP_ADD ] = hash_add, + [ IPSET_OP_DEL ] = hash_del, + [ IPSET_OP_TEST ] = hash_test +}; void hash_flush(struct ipset *set) diff --git a/src/ipset/ipset_hash_ip.c b/src/ipset/ipset_hash_ip.c index 4e114cc5a..b0bc670fb 100644 --- a/src/ipset/ipset_hash_ip.c +++ b/src/ipset/ipset_hash_ip.c @@ -188,14 +188,14 @@ static int hash_ip_create(struct ipset *set, struct ipset_param *param) { hash_create(set, param); - if (param->option.family == AF_INET) { - set->dsize = sizeof(elem4_t); - set->hash_len = offsetof(elem4_t, comment); - set->variant = &hash_ip_variant4; - } else { + if (param->option.family == AF_INET6) { set->dsize = sizeof(elem6_t); set->hash_len = offsetof(elem6_t, comment); set->variant = &hash_ip_variant6; + } else { + set->dsize = sizeof(elem4_t); + set->hash_len = offsetof(elem4_t, comment); + set->variant = &hash_ip_variant4; } return EDPVS_OK; diff --git a/src/ipset/ipset_hash_ipport.c b/src/ipset/ipset_hash_ipport.c index f94ce34a5..ebf39a5b8 100644 --- a/src/ipset/ipset_hash_ipport.c +++ b/src/ipset/ipset_hash_ipport.c @@ -268,14 +268,14 @@ hash_ipport_create(struct ipset *set, struct ipset_param *param) { hash_create(set, param); - if (param->option.family == AF_INET) { - set->dsize = sizeof(elem4_t); - set->hash_len = offsetof(elem4_t, comment); - set->variant = &hash_ipport_variant4; - } else { + if (param->option.family == AF_INET6) { set->dsize = sizeof(elem6_t); set->hash_len = offsetof(elem6_t, comment); set->variant = &hash_ipport_variant6; + } else { + set->dsize = sizeof(elem4_t); + set->hash_len = offsetof(elem4_t, comment); + set->variant = &hash_ipport_variant4; } return EDPVS_OK; diff --git a/src/ipset/ipset_hash_ipportip.c b/src/ipset/ipset_hash_ipportip.c index 87234e4e7..64823550e 100644 --- a/src/ipset/ipset_hash_ipportip.c +++ b/src/ipset/ipset_hash_ipportip.c @@ -284,14 +284,14 @@ hash_ipportip_create(struct ipset *set, struct ipset_param *param) { hash_create(set, param); - if (param->option.family == AF_INET) { - set->dsize = sizeof(elem4_t); - set->hash_len = offsetof(elem4_t, comment); - set->variant = &hash_ipportip_variant4; - } else { + if (param->option.family == AF_INET6) { set->dsize = sizeof(elem6_t); set->hash_len = offsetof(elem6_t, comment); set->variant = &hash_ipportip_variant6; + } else { + set->dsize = sizeof(elem4_t); + set->hash_len = offsetof(elem4_t, comment); + set->variant = &hash_ipportip_variant4; } return EDPVS_OK; diff --git a/src/ipset/ipset_hash_ipportnet.c b/src/ipset/ipset_hash_ipportnet.c index 0c040e7da..78a42008d 100644 --- a/src/ipset/ipset_hash_ipportnet.c +++ b/src/ipset/ipset_hash_ipportnet.c @@ -285,10 +285,10 @@ hash_ipportnet_create(struct ipset *set, struct ipset_param *param) set->dsize = sizeof(elem_t); set->hash_len = offsetof(elem_t, comment); - if (param->option.family == AF_INET) - set->variant = &hash_ipportnet_variant4; - else + if (param->option.family == AF_INET6) set->variant = &hash_ipportnet_variant6; + else + set->variant = &hash_ipportnet_variant4; return EDPVS_OK; } diff --git a/src/ipset/ipset_hash_net.c b/src/ipset/ipset_hash_net.c index 7bbee349d..fb9084c32 100644 --- a/src/ipset/ipset_hash_net.c +++ b/src/ipset/ipset_hash_net.c @@ -219,10 +219,10 @@ hash_net_create(struct ipset *set, struct ipset_param *param) set->dsize = sizeof(elem_t); set->hash_len = offsetof(elem_t, comment); - if (param->option.family == AF_INET) - set->variant = &hash_net_variant4; - else + if (param->option.family == AF_INET6) set->variant = &hash_net_variant6; + else + set->variant = &hash_net_variant4; return EDPVS_OK; } diff --git a/src/ipset/ipset_hash_netport.c b/src/ipset/ipset_hash_netport.c index 975eef330..fb17917d4 100644 --- a/src/ipset/ipset_hash_netport.c +++ b/src/ipset/ipset_hash_netport.c @@ -269,10 +269,10 @@ hash_netport_create(struct ipset *set, struct ipset_param *param) set->dsize = sizeof(elem_t); set->hash_len = offsetof(elem_t, comment); - if (param->option.family == AF_INET) - set->variant = &hash_netport_variant4; - else + if (param->option.family == AF_INET6) set->variant = &hash_netport_variant6; + else + set->variant = &hash_netport_variant4; return EDPVS_OK; } diff --git a/src/ipset/ipset_hash_netportiface.c b/src/ipset/ipset_hash_netportiface.c index 7b15c4bb5..ef00c5d32 100644 --- a/src/ipset/ipset_hash_netportiface.c +++ b/src/ipset/ipset_hash_netportiface.c @@ -284,10 +284,10 @@ hash_netportiface_create(struct ipset *set, struct ipset_param *param) set->dsize = sizeof(elem_t); set->hash_len = offsetof(elem_t, dev); - if (param->option.family == AF_INET) - set->variant = &hash_netportiface_variant4; - else + if (param->option.family == AF_INET6) set->variant = &hash_netportiface_variant6; + else + set->variant = &hash_netportiface_variant4; return EDPVS_OK; } diff --git a/src/ipset/ipset_hash_netportnet.c b/src/ipset/ipset_hash_netportnet.c index 29dedc4f6..16b14ec55 100644 --- a/src/ipset/ipset_hash_netportnet.c +++ b/src/ipset/ipset_hash_netportnet.c @@ -287,10 +287,10 @@ hash_netportnet_create(struct ipset *set, struct ipset_param *param) set->dsize = sizeof(elem_t); set->hash_len = offsetof(elem_t, comment); - if (param->option.family == AF_INET) - set->variant = &hash_netportnet_variant4; - else + if (param->option.family == AF_INET6) set->variant = &hash_netportnet_variant6; + else + set->variant = &hash_netportnet_variant4; return EDPVS_OK; } diff --git a/src/ipset/ipset_hash_netportnetport.c b/src/ipset/ipset_hash_netportnetport.c index 5849c3d46..2cf0090a5 100644 --- a/src/ipset/ipset_hash_netportnetport.c +++ b/src/ipset/ipset_hash_netportnetport.c @@ -299,10 +299,10 @@ hash_netportnetport_create(struct ipset *set, struct ipset_param *param) set->dsize = sizeof(elem_t); set->hash_len = offsetof(elem_t, comment); - if (param->option.family == AF_INET) - set->variant = &hash_netportnetport_variant4; - else + if (param->option.family == AF_INET6) set->variant = &hash_netportnetport_variant6; + else + set->variant = &hash_netportnetport_variant4; return EDPVS_OK; } diff --git a/src/ipvs/ip_vs_blklst.c b/src/ipvs/ip_vs_blklst.c index 0afebc6cb..25491a076 100644 --- a/src/ipvs/ip_vs_blklst.c +++ b/src/ipvs/ip_vs_blklst.c @@ -35,86 +35,198 @@ * */ -#define DPVS_BLKLST_TAB_BITS 16 -#define DPVS_BLKLST_TAB_SIZE (1 << DPVS_BLKLST_TAB_BITS) -#define DPVS_BLKLST_TAB_MASK (DPVS_BLKLST_TAB_SIZE - 1) - -#define this_blklst_tab (RTE_PER_LCORE(dp_vs_blklst_tab)) -#define this_num_blklsts (RTE_PER_LCORE(num_blklsts)) +#define DPVS_BLKLST_TAB_BITS 16 +#define DPVS_BLKLST_TAB_SIZE (1 << DPVS_BLKLST_TAB_BITS) +#define DPVS_BLKLST_TAB_MASK (DPVS_BLKLST_TAB_SIZE - 1) +#define this_blklst_tab (RTE_PER_LCORE(dp_vs_blklst_tab)) +#define this_num_blklsts (RTE_PER_LCORE(num_blklsts)) + +#define DPVS_BLKLST_IPSET_TAB_BITS 8 +#define DPVS_BLKLST_IPSET_TAB_SIZE (1 << DPVS_BLKLST_IPSET_TAB_BITS) +#define DPVS_BLKLST_IPSET_TAB_MASK (DPVS_BLKLST_IPSET_TAB_SIZE - 1) +#define this_blklst_ipset_tab (RTE_PER_LCORE(dp_vs_blklst_ipset_tab)) +#define this_num_blklsts_ipset (RTE_PER_LCORE(num_blklsts_ipset)) static RTE_DEFINE_PER_LCORE(struct list_head *, dp_vs_blklst_tab); -static RTE_DEFINE_PER_LCORE(rte_atomic32_t, num_blklsts); +static RTE_DEFINE_PER_LCORE(uint32_t, num_blklsts); + +static RTE_DEFINE_PER_LCORE(struct list_head *, dp_vs_blklst_ipset_tab); +static RTE_DEFINE_PER_LCORE(uint32_t, num_blklsts_ipset); static uint32_t dp_vs_blklst_rnd; +static inline void blklst_fill_conf(const struct blklst_entry *entry, + struct dp_vs_blklst_conf *conf) +{ + memset(conf, 0, sizeof(*conf)); + conf->vaddr = entry->vaddr; + conf->vport = entry->vport; + conf->proto = entry->proto; + conf->af = entry->af; + conf->subject = entry->subject; + if (entry->set) + strncpy(conf->ipset, entry->set->name, sizeof(conf->ipset) - 1); +} + static inline uint32_t blklst_hashkey(const union inet_addr *vaddr, - const union inet_addr *blklst) + uint16_t vport, const union inet_addr *subject, bool ipset) { /* jhash hurts performance, we do not use rte_jhash_2words here */ - return ((rte_be_to_cpu_32(vaddr->in.s_addr) * 31 - + rte_be_to_cpu_32(blklst->in.s_addr)) * 31 - + dp_vs_blklst_rnd) & DPVS_BLKLST_TAB_MASK; + if (ipset) + return ((((vaddr->in.s_addr * 31) ^ vport) * 131) + ^ dp_vs_blklst_rnd) & DPVS_BLKLST_IPSET_TAB_MASK; + + return ((((vaddr->in.s_addr * 31) ^ subject->in.s_addr) * 131) + ^ (vport ^ dp_vs_blklst_rnd)) & DPVS_BLKLST_TAB_MASK; } -struct blklst_entry *dp_vs_blklst_lookup(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *blklst) +static inline struct blklst_entry *dp_vs_blklst_ip_lookup( + int af, uint8_t proto, const union inet_addr *vaddr, + uint16_t vport, const union inet_addr *subject) { unsigned hashkey; - struct blklst_entry *blklst_node; - - hashkey = blklst_hashkey(vaddr, blklst); - list_for_each_entry(blklst_node, &this_blklst_tab[hashkey], list) { - if (blklst_node->af == af && blklst_node->proto == proto && - blklst_node->vport == vport && - inet_addr_equal(af, &blklst_node->vaddr, vaddr) && - inet_addr_equal(af, &blklst_node->blklst, blklst)) - return blklst_node; + struct blklst_entry *entry; + + hashkey = blklst_hashkey(vaddr, vport, subject, false); + list_for_each_entry(entry, &this_blklst_tab[hashkey], list) { + if (entry->af == af && entry->proto == proto && + entry->vport == vport && + inet_addr_equal(af, &entry->vaddr, vaddr) && + inet_addr_equal(af, &entry->subject, subject)) + return entry; } + return NULL; } -static int dp_vs_blklst_add_lcore(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *blklst) +static inline struct blklst_entry *dp_vs_blklst_ipset_lookup( + int af, uint8_t proto, const union inet_addr *vaddr, + uint16_t vport, const char *ipset) { unsigned hashkey; - struct blklst_entry *new, *blklst_node; + struct blklst_entry *entry; - blklst_node = dp_vs_blklst_lookup(af, proto, vaddr, vport, blklst); - if (blklst_node) { - return EDPVS_EXIST; + hashkey = blklst_hashkey(vaddr, vport, NULL, true); + list_for_each_entry(entry, &this_blklst_ipset_tab[hashkey], list) { + if (entry->af == af && entry->proto == proto && entry->vport == vport && + inet_addr_equal(af, &entry->vaddr, vaddr) && + !strncmp(entry->set->name, ipset, sizeof(entry->set->name))) + return entry; + } + + return NULL; +} + +static bool dp_vs_blklst_ip_match_set(int af, uint8_t proto, + const union inet_addr *vaddr, uint16_t vport, + struct rte_mbuf *mbuf) +{ + bool res = false; + unsigned hashkey; + struct blklst_entry *entry; + + hashkey = blklst_hashkey(vaddr, vport, NULL, true); + list_for_each_entry(entry, &this_blklst_ipset_tab[hashkey], list) { + if (entry->af == af && entry->proto == proto && + entry->vport == vport && + inet_addr_equal(af, &entry->vaddr, vaddr)) { + rte_pktmbuf_prepend(mbuf, mbuf->l2_len); + res = elem_in_set(entry->set, mbuf, entry->dst_match); + rte_pktmbuf_adj(mbuf, mbuf->l2_len); + if (res) + break; + } } + return res; +} + +static struct blklst_entry *dp_vs_blklst_lookup(const struct dp_vs_blklst_conf *conf) +{ + struct blklst_entry *entry; - hashkey = blklst_hashkey(vaddr, blklst); + entry = dp_vs_blklst_ip_lookup(conf->af, conf->proto, &conf->vaddr, conf->vport, + &conf->subject); + if (entry) + return entry; + + return dp_vs_blklst_ipset_lookup(conf->af, conf->proto, &conf->vaddr, conf->vport, + conf->ipset); +} + +bool dp_vs_blklst_filtered(int af, uint8_t proto, const union inet_addr *vaddr, + uint16_t vport, const union inet_addr *subject, struct rte_mbuf *mbuf) +{ + if (dp_vs_blklst_ip_lookup(af, proto, vaddr, vport, subject)) + return true; + + return dp_vs_blklst_ip_match_set(af, proto, vaddr, vport, mbuf); +} + +static int dp_vs_blklst_add_lcore(const struct dp_vs_blklst_conf *conf) +{ + unsigned hashkey; + struct blklst_entry *new; + bool is_ipset = conf->ipset[0] != '\0'; + + if (dp_vs_blklst_lookup(conf)) + return EDPVS_EXIST; + + hashkey = blklst_hashkey(&conf->vaddr, conf->vport, &conf->subject, is_ipset); new = rte_zmalloc("new_blklst_entry", sizeof(struct blklst_entry), 0); if (unlikely(new == NULL)) return EDPVS_NOMEM; - new->af = af; - new->proto = proto; - new->vport = vport; - memcpy(&new->vaddr, vaddr, sizeof(union inet_addr)); - memcpy(&new->blklst, blklst, sizeof(union inet_addr)); - list_add(&new->list, &this_blklst_tab[hashkey]); - rte_atomic32_inc(&this_num_blklsts); + new->vaddr = conf->vaddr; + new->vport = conf->vport; + new->proto = conf->proto; + new->af = conf->af; + + if (is_ipset) { + new->set = ipset_get(conf->ipset); + if (!new->set) { + RTE_LOG(ERR, SERVICE, "[%2d] %s: ipset %s not found\n", + rte_lcore_id(), __func__, conf->ipset); + rte_free(new); + return EDPVS_INVAL; + } + // Notes: Reassess it when new ipset types added! + if (!strcmp(new->set->type->name, "hash:ip,port,net") || + !strcmp(new->set->type->name, "hash:ip,port,ip") || + !strcmp(new->set->type->name, "hash:net,port,net")) + new->dst_match = true; + else + new->dst_match = false; + list_add(&new->list, &this_blklst_ipset_tab[hashkey]); + ++this_num_blklsts_ipset; + } else { + new->subject = conf->subject; + list_add(&new->list, &this_blklst_tab[hashkey]); + ++this_num_blklsts; + } return EDPVS_OK; } -static int dp_vs_blklst_del_lcore(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *blklst) +static int dp_vs_blklst_del_lcore(const struct dp_vs_blklst_conf *conf) { - struct blklst_entry *blklst_node; - - blklst_node = dp_vs_blklst_lookup(af, proto, vaddr, vport, blklst); - if (blklst_node != NULL) { - list_del(&blklst_node->list); - rte_free(blklst_node); - rte_atomic32_dec(&this_num_blklsts); - return EDPVS_OK; + struct blklst_entry *entry; + + entry = dp_vs_blklst_lookup(conf); + if (!entry) + return EDPVS_NOTEXIST; + + if (entry->set) { /* ipset entry */ + list_del(&entry->list); + ipset_put(entry->set); + --this_num_blklsts_ipset; + } else { /* ip entry */ + list_del(&entry->list); + --this_num_blklsts; } - return EDPVS_NOTEXIST; + rte_free(entry); + return EDPVS_OK; } static uint32_t blklst_msg_seq(void) @@ -123,42 +235,33 @@ static uint32_t blklst_msg_seq(void) return counter++; } -static int dp_vs_blklst_add(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *blklst) +static int dp_vs_blklst_add(const struct dp_vs_blklst_conf *conf) { lcoreid_t cid = rte_lcore_id(); int err; struct dpvs_msg *msg; - struct dp_vs_blklst_conf cf; if (cid != rte_get_main_lcore()) { RTE_LOG(INFO, SERVICE, "%s must set from master lcore\n", __func__); return EDPVS_NOTSUPP; } - memset(&cf, 0, sizeof(struct dp_vs_blklst_conf)); - memcpy(&(cf.vaddr), vaddr,sizeof(union inet_addr)); - memcpy(&(cf.blklst), blklst, sizeof(union inet_addr)); - cf.af = af; - cf.vport = vport; - cf.proto = proto; - - /*set blklst ip on master lcore*/ - err = dp_vs_blklst_add_lcore(af, proto, vaddr, vport, blklst); + /* master lcore */ + err = dp_vs_blklst_add_lcore(conf); if (err && err != EDPVS_EXIST) { - RTE_LOG(ERR, SERVICE, "[%s] fail to set blklst ip -- %s\n", __func__, dpvs_strerror(err)); + RTE_LOG(ERR, SERVICE, "%s: fail to add blklst entry -- %s\n", __func__, dpvs_strerror(err)); return err; } - /*set blklst ip on all slave lcores*/ + /* slave lcores */ msg = msg_make(MSG_TYPE_BLKLST_ADD, blklst_msg_seq(), DPVS_MSG_MULTICAST, - cid, sizeof(struct dp_vs_blklst_conf), &cf); + cid, sizeof(struct dp_vs_blklst_conf), conf); if (unlikely(!msg)) return EDPVS_NOMEM; err = multicast_msg_send(msg, DPVS_MSG_F_ASYNC, NULL); if (err != EDPVS_OK) { msg_destroy(&msg); - RTE_LOG(INFO, SERVICE, "[%s] fail to send multicast message\n", __func__); + RTE_LOG(INFO, SERVICE, "%s: fail to send multicast message\n", __func__); return err; } msg_destroy(&msg); @@ -166,35 +269,27 @@ static int dp_vs_blklst_add(int af, uint8_t proto, const union inet_addr *vaddr, return EDPVS_OK; } -static int dp_vs_blklst_del(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *blklst) +static int dp_vs_blklst_del(const struct dp_vs_blklst_conf *conf) { lcoreid_t cid = rte_lcore_id(); int err; struct dpvs_msg *msg; - struct dp_vs_blklst_conf cf; if (cid != rte_get_main_lcore()) { RTE_LOG(INFO, SERVICE, "%s must set from master lcore\n", __func__); return EDPVS_NOTSUPP; } - memset(&cf, 0, sizeof(struct dp_vs_blklst_conf)); - memcpy(&(cf.vaddr), vaddr,sizeof(union inet_addr)); - memcpy(&(cf.blklst), blklst, sizeof(union inet_addr)); - cf.af = af; - cf.vport = vport; - cf.proto = proto; - - /*del blklst ip on master lcores*/ - err = dp_vs_blklst_del_lcore(af, proto, vaddr, vport, blklst); + /* master lcore */ + err = dp_vs_blklst_del_lcore(conf); if (err) { + RTE_LOG(ERR, SERVICE, "%s: fail to del blklst entry -- %s\n", __func__, dpvs_strerror(err)); return err; } - /*del blklst ip on all slave lcores*/ + /* slave lcores */ msg = msg_make(MSG_TYPE_BLKLST_DEL, blklst_msg_seq(), DPVS_MSG_MULTICAST, - cid, sizeof(struct dp_vs_blklst_conf), &cf); + cid, sizeof(struct dp_vs_blklst_conf), conf); if (!msg) return EDPVS_NOMEM; err = multicast_msg_send(msg, DPVS_MSG_F_ASYNC, NULL); @@ -212,32 +307,52 @@ void dp_vs_blklst_flush(struct dp_vs_service *svc) { int hash; struct blklst_entry *entry, *next; + struct dp_vs_blklst_conf conf; for (hash = 0; hash < DPVS_BLKLST_TAB_SIZE; hash++) { list_for_each_entry_safe(entry, next, &this_blklst_tab[hash], list) { if (entry->af == svc->af - && entry->vport == svc->port - && entry->proto == svc->proto - && inet_addr_equal(svc->af, &entry->vaddr, &svc->addr)) - dp_vs_blklst_del(svc->af, entry->proto, &entry->vaddr, - entry->vport, &entry->blklst); + && entry->vport == svc->port + && entry->proto == svc->proto + && inet_addr_equal(svc->af, &entry->vaddr, &svc->addr)) { + blklst_fill_conf(entry, &conf); + dp_vs_blklst_del(&conf); + } + } + } + + for (hash = 0; hash < DPVS_BLKLST_IPSET_TAB_SIZE; hash++) { + list_for_each_entry_safe(entry, next, &this_blklst_ipset_tab[hash], list) { + if (entry->af == svc->af + && entry->vport == svc->port + && entry->proto == svc->proto + && inet_addr_equal(svc->af, &entry->vaddr, &svc->addr)) { + blklst_fill_conf(entry, &conf); + dp_vs_blklst_del(&conf); + } } } - return; } static void dp_vs_blklst_flush_all(void) { - struct blklst_entry *entry, *next; int hash; + struct blklst_entry *entry, *next; + struct dp_vs_blklst_conf conf; for (hash = 0; hash < DPVS_BLKLST_TAB_SIZE; hash++) { list_for_each_entry_safe(entry, next, &this_blklst_tab[hash], list) { - dp_vs_blklst_del(entry->af, entry->proto, &entry->vaddr, - entry->vport, &entry->blklst); + blklst_fill_conf(entry, &conf); + dp_vs_blklst_del(&conf); + } + } + + for (hash = 0; hash < DPVS_BLKLST_IPSET_TAB_SIZE; hash++) { + list_for_each_entry_safe(entry, next, &this_blklst_ipset_tab[hash], list) { + blklst_fill_conf(entry, &conf); + dp_vs_blklst_del(&conf); } } - return; } /* @@ -245,40 +360,19 @@ static void dp_vs_blklst_flush_all(void) */ static int blklst_sockopt_set(sockoptid_t opt, const void *conf, size_t size) { - const struct dp_vs_blklst_conf *blklst_conf = conf; - int err; - - if (!conf && size < sizeof(*blklst_conf)) + if (!conf && size < sizeof(struct dp_vs_blklst_conf)) return EDPVS_INVAL; switch (opt) { - case SOCKOPT_SET_BLKLST_ADD: - err = dp_vs_blklst_add(blklst_conf->af, - blklst_conf->proto, &blklst_conf->vaddr, - blklst_conf->vport, &blklst_conf->blklst); - break; - case SOCKOPT_SET_BLKLST_DEL: - err = dp_vs_blklst_del(blklst_conf->af, - blklst_conf->proto, &blklst_conf->vaddr, - blklst_conf->vport, &blklst_conf->blklst); - break; - default: - err = EDPVS_NOTSUPP; - break; + case SOCKOPT_SET_BLKLST_ADD: + return dp_vs_blklst_add(conf); + case SOCKOPT_SET_BLKLST_DEL: + return dp_vs_blklst_del(conf); + default: + return EDPVS_NOTSUPP; } - return err; -} - -static void blklst_fill_conf(struct dp_vs_blklst_conf *cf, - const struct blklst_entry *entry) -{ - memset(cf, 0 ,sizeof(*cf)); - cf->af = entry->af; - cf->vaddr = entry->vaddr; - cf->blklst = entry->blklst; - cf->proto = entry->proto; - cf->vport = entry->vport; + return EDPVS_OK; } static int blklst_sockopt_get(sockoptid_t opt, const void *conf, size_t size, @@ -289,7 +383,7 @@ static int blklst_sockopt_get(sockoptid_t opt, const void *conf, size_t size, size_t naddr, hash; int off = 0; - naddr = rte_atomic32_read(&this_num_blklsts); + naddr = this_num_blklsts + this_num_blklsts_ipset; *outsize = sizeof(struct dp_vs_blklst_conf_array) + naddr * sizeof(struct dp_vs_blklst_conf); *out = rte_calloc(NULL, 1, *outsize, 0); @@ -302,45 +396,52 @@ static int blklst_sockopt_get(sockoptid_t opt, const void *conf, size_t size, list_for_each_entry(entry, &this_blklst_tab[hash], list) { if (off >= naddr) break; - blklst_fill_conf(&array->blklsts[off++], entry); + blklst_fill_conf(entry, &array->blklsts[off++]); + } + } + + for (hash = 0; hash < DPVS_BLKLST_IPSET_TAB_SIZE; hash++) { + list_for_each_entry(entry, &this_blklst_ipset_tab[hash], list) { + if (off >= naddr) + break; + blklst_fill_conf(entry, &array->blklsts[off++]); } } return EDPVS_OK; } - static int blklst_msg_process(bool add, struct dpvs_msg *msg) { - struct dp_vs_blklst_conf *cf; + struct dp_vs_blklst_conf *conf; int err; assert(msg); if (msg->len != sizeof(struct dp_vs_blklst_conf)){ - RTE_LOG(ERR, SERVICE, "%s: bad message.\n", __func__); + RTE_LOG(ERR, SERVICE, "%s: bad message\n", __func__); return EDPVS_INVAL; } - cf = (struct dp_vs_blklst_conf *)msg->data; + conf = (struct dp_vs_blklst_conf *)msg->data; if (add) { - err = dp_vs_blklst_add_lcore(cf->af, cf->proto, &cf->vaddr, cf->vport, &cf->blklst); - if (err && err != EDPVS_EXIST) { - RTE_LOG(ERR, SERVICE, "%s: fail to add blklst: %s.\n", __func__, dpvs_strerror(err)); - } - } - else { - err = dp_vs_blklst_del_lcore(cf->af, cf->proto, &cf->vaddr, cf->vport, &cf->blklst); + err = dp_vs_blklst_add_lcore(conf); + if (err && err != EDPVS_EXIST) + RTE_LOG(ERR, SERVICE, "%s: fail to add blklst: %s\n", __func__, dpvs_strerror(err)); + } else { + err = dp_vs_blklst_del_lcore(conf); + if (err && err != EDPVS_NOTEXIST) + RTE_LOG(ERR, SERVICE, "%s: fail to del blklst: %s\n", __func__, dpvs_strerror(err)); } return err; } -inline static int blklst_add_msg_cb(struct dpvs_msg *msg) +static inline int blklst_add_msg_cb(struct dpvs_msg *msg) { return blklst_msg_process(true, msg); } -inline static int blklst_del_msg_cb(struct dpvs_msg *msg) +static inline int blklst_del_msg_cb(struct dpvs_msg *msg) { return blklst_msg_process(false, msg); } @@ -358,17 +459,29 @@ static struct dpvs_sockopts blklst_sockopts = { static int blklst_lcore_init(void *args) { int i; + if (!rte_lcore_is_enabled(rte_lcore_id())) - return EDPVS_DISABLED; - this_blklst_tab = rte_malloc(NULL, - sizeof(struct list_head) * DPVS_BLKLST_TAB_SIZE, - RTE_CACHE_LINE_SIZE); + return EDPVS_DISABLED; + + this_num_blklsts = 0; + this_num_blklsts_ipset = 0; + + this_blklst_tab = rte_malloc(NULL, sizeof(struct list_head) * + DPVS_BLKLST_TAB_SIZE, RTE_CACHE_LINE_SIZE); if (!this_blklst_tab) return EDPVS_NOMEM; - for (i = 0; i < DPVS_BLKLST_TAB_SIZE; i++) INIT_LIST_HEAD(&this_blklst_tab[i]); + this_blklst_ipset_tab = rte_malloc(NULL, sizeof(struct list_head) * + DPVS_BLKLST_IPSET_TAB_SIZE, RTE_CACHE_LINE_SIZE); + if (!this_blklst_ipset_tab) { + rte_free(this_blklst_tab); + return EDPVS_NOMEM; + } + for (i = 0; i < DPVS_BLKLST_IPSET_TAB_SIZE; i++) + INIT_LIST_HEAD(&this_blklst_ipset_tab[i]); + return EDPVS_OK; } @@ -383,6 +496,12 @@ static int blklst_lcore_term(void *args) rte_free(this_blklst_tab); this_blklst_tab = NULL; } + + if (this_blklst_ipset_tab) { + rte_free(this_blklst_ipset_tab); + this_blklst_ipset_tab = NULL; + } + return EDPVS_OK; } @@ -392,13 +511,11 @@ int dp_vs_blklst_init(void) lcoreid_t cid; struct dpvs_msg_type msg_type; - rte_atomic32_set(&this_num_blklsts, 0); - rte_eal_mp_remote_launch(blklst_lcore_init, NULL, CALL_MAIN); RTE_LCORE_FOREACH_WORKER(cid) { if ((err = rte_eal_wait_lcore(cid)) < 0) { - RTE_LOG(WARNING, SERVICE, "%s: lcore %d: %s.\n", - __func__, cid, dpvs_strerror(err)); + RTE_LOG(WARNING, SERVICE, "[%02d] %s: blklst init failed -- %s\n", + cid, __func__, dpvs_strerror(err)); return err; } } @@ -411,7 +528,8 @@ int dp_vs_blklst_init(void) msg_type.unicast_msg_cb = blklst_add_msg_cb; err = msg_type_mc_register(&msg_type); if (err != EDPVS_OK) { - RTE_LOG(ERR, SERVICE, "%s: fail to register msg.\n", __func__); + RTE_LOG(ERR, SERVICE, "%s: register BLKLST_ADD msg failed -- %s\n", + __func__, dpvs_strerror(err)); return err; } @@ -423,12 +541,17 @@ int dp_vs_blklst_init(void) msg_type.unicast_msg_cb = blklst_del_msg_cb; err = msg_type_mc_register(&msg_type); if (err != EDPVS_OK) { - RTE_LOG(ERR, SERVICE, "%s: fail to register msg.\n", __func__); + RTE_LOG(ERR, SERVICE, "%s: register BLKLST_DEL msg failed -- %s\n", + __func__, dpvs_strerror(err)); return err; } - if ((err = sockopt_register(&blklst_sockopts)) != EDPVS_OK) + if ((err = sockopt_register(&blklst_sockopts)) != EDPVS_OK) { + RTE_LOG(ERR, SERVICE, "%s: register sockopts failed -- %s\n", + __func__, dpvs_strerror(err)); return err; + } + dp_vs_blklst_rnd = (uint32_t)random(); return EDPVS_OK; @@ -438,15 +561,42 @@ int dp_vs_blklst_term(void) { int err; lcoreid_t cid; + struct dpvs_msg_type msg_type; - if ((err = sockopt_unregister(&blklst_sockopts)) != EDPVS_OK) - return err; + if ((err = sockopt_unregister(&blklst_sockopts)) != EDPVS_OK) { + RTE_LOG(WARNING, SERVICE, "%s: unregister sockopts failed -- %s\n", + __func__, dpvs_strerror(err)); + } + + memset(&msg_type, 0, sizeof(struct dpvs_msg_type)); + msg_type.type = MSG_TYPE_BLKLST_DEL; + msg_type.mode = DPVS_MSG_MULTICAST; + msg_type.prio = MSG_PRIO_NORM; + msg_type.cid = rte_lcore_id(); + msg_type.unicast_msg_cb = blklst_del_msg_cb; + err = msg_type_mc_unregister(&msg_type); + if (err != EDPVS_OK) { + RTE_LOG(ERR, SERVICE, "%s: unregister BLKLST_DEL msg failed -- %s\n", + __func__, dpvs_strerror(err)); + } + + memset(&msg_type, 0, sizeof(struct dpvs_msg_type)); + msg_type.type = MSG_TYPE_BLKLST_ADD; + msg_type.mode = DPVS_MSG_MULTICAST; + msg_type.prio = MSG_PRIO_NORM; + msg_type.cid = rte_lcore_id(); + msg_type.unicast_msg_cb = blklst_add_msg_cb; + err = msg_type_mc_unregister(&msg_type); + if (err != EDPVS_OK) { + RTE_LOG(ERR, SERVICE, "%s: unregister BLKLST_ADD msg failed -- %s\n", + __func__, dpvs_strerror(err)); + } rte_eal_mp_remote_launch(blklst_lcore_term, NULL, CALL_MAIN); RTE_LCORE_FOREACH_WORKER(cid) { if ((err = rte_eal_wait_lcore(cid)) < 0) { - RTE_LOG(WARNING, SERVICE, "%s: lcore %d: %s.\n", - __func__, cid, dpvs_strerror(err)); + RTE_LOG(WARNING, SERVICE, "[%02d] %s: blklst termination failed -- %s\n", + cid, __func__, dpvs_strerror(err)); } } diff --git a/src/ipvs/ip_vs_core.c b/src/ipvs/ip_vs_core.c index b92e98496..f01f41ba0 100644 --- a/src/ipvs/ip_vs_core.c +++ b/src/ipvs/ip_vs_core.c @@ -984,9 +984,8 @@ static int __dp_vs_in(void *priv, struct rte_mbuf *mbuf, /* packet belongs to existing connection ? */ conn = prot->conn_lookup(prot, &iph, mbuf, &dir, false, &drop, &peer_cid); - if (unlikely(drop)) { - RTE_LOG(DEBUG, IPVS, "%s: deny ip try to visit.\n", __func__); + RTE_LOG(DEBUG, IPVS, "%s: packet dropped by ipvs acl\n", __func__); return INET_DROP; } diff --git a/src/ipvs/ip_vs_proto_sctp.c b/src/ipvs/ip_vs_proto_sctp.c index 28b067ae1..be2330e5f 100644 --- a/src/ipvs/ip_vs_proto_sctp.c +++ b/src/ipvs/ip_vs_proto_sctp.c @@ -70,14 +70,14 @@ static struct dp_vs_conn *sctp_conn_lookup(struct dp_vs_proto *proto, if (unlikely(!sch)) return NULL; - if (dp_vs_blklst_lookup(iph->af, iph->proto, &iph->daddr, sh->dest_port, - &iph->saddr)) { + if (dp_vs_blklst_filtered(iph->af, iph->proto, &iph->daddr, sh->dest_port, + &iph->saddr, mbuf)) { *drop = true; return NULL; } - if (!dp_vs_whtlst_allow(iph->af, iph->proto, &iph->daddr, sh->dest_port, - &iph->saddr)) { + if (dp_vs_whtlst_filtered(iph->af, iph->proto, &iph->daddr, sh->dest_port, + &iph->saddr, mbuf)) { *drop = true; return NULL; } diff --git a/src/ipvs/ip_vs_proto_tcp.c b/src/ipvs/ip_vs_proto_tcp.c index 8c7edb501..b10aedd49 100644 --- a/src/ipvs/ip_vs_proto_tcp.c +++ b/src/ipvs/ip_vs_proto_tcp.c @@ -831,13 +831,14 @@ tcp_conn_lookup(struct dp_vs_proto *proto, const struct dp_vs_iphdr *iph, if (unlikely(!th)) return NULL; - if (dp_vs_blklst_lookup(iph->af, iph->proto, &iph->daddr, - th->dest, &iph->saddr)) { + if (dp_vs_blklst_filtered(iph->af, iph->proto, &iph->daddr, + th->dest, &iph->saddr, mbuf)) { *drop = true; return NULL; } - if (!dp_vs_whtlst_allow(iph->af, iph->proto, &iph->daddr, th->dest, &iph->saddr)) { + if (dp_vs_whtlst_filtered(iph->af, iph->proto, &iph->daddr, + th->dest, &iph->saddr, mbuf)) { *drop = true; return NULL; } diff --git a/src/ipvs/ip_vs_proto_udp.c b/src/ipvs/ip_vs_proto_udp.c index df58fc924..b0fa040f2 100644 --- a/src/ipvs/ip_vs_proto_udp.c +++ b/src/ipvs/ip_vs_proto_udp.c @@ -235,14 +235,14 @@ udp_conn_lookup(struct dp_vs_proto *proto, if (unlikely(!uh)) return NULL; - if (dp_vs_blklst_lookup(iph->af, iph->proto, &iph->daddr, - uh->dst_port, &iph->saddr)) { + if (dp_vs_blklst_filtered(iph->af, iph->proto, &iph->daddr, + uh->dst_port, &iph->saddr, mbuf)) { *drop = true; return NULL; } - if (!dp_vs_whtlst_allow(iph->af, iph->proto, &iph->daddr, - uh->dst_port, &iph->saddr)) { + if (dp_vs_whtlst_filtered(iph->af, iph->proto, &iph->daddr, + uh->dst_port, &iph->saddr, mbuf)) { *drop = true; return NULL; } diff --git a/src/ipvs/ip_vs_synproxy.c b/src/ipvs/ip_vs_synproxy.c index 5378083b7..305b84f40 100644 --- a/src/ipvs/ip_vs_synproxy.c +++ b/src/ipvs/ip_vs_synproxy.c @@ -758,13 +758,14 @@ int dp_vs_synproxy_syn_rcv(int af, struct rte_mbuf *mbuf, } /* drop packet from blacklist */ - if (dp_vs_blklst_lookup(iph->af, iph->proto, &iph->daddr, - th->dest, &iph->saddr)) { + if (dp_vs_blklst_filtered(iph->af, iph->proto, &iph->daddr, + th->dest, &iph->saddr, mbuf)) { goto syn_rcv_out; } /* drop packet if not in whitelist */ - if (!dp_vs_whtlst_allow(iph->af, iph->proto, &iph->daddr, th->dest, &iph->saddr)) { + if (dp_vs_whtlst_filtered(iph->af, iph->proto, &iph->daddr, + th->dest, &iph->saddr, mbuf)) { goto syn_rcv_out; } } else { diff --git a/src/ipvs/ip_vs_whtlst.c b/src/ipvs/ip_vs_whtlst.c index bea11c922..672077456 100644 --- a/src/ipvs/ip_vs_whtlst.c +++ b/src/ipvs/ip_vs_whtlst.c @@ -38,103 +38,257 @@ #define DPVS_WHTLST_TAB_BITS 16 #define DPVS_WHTLST_TAB_SIZE (1 << DPVS_WHTLST_TAB_BITS) #define DPVS_WHTLST_TAB_MASK (DPVS_WHTLST_TAB_SIZE - 1) - #define this_whtlst_tab (RTE_PER_LCORE(dp_vs_whtlst_tab)) #define this_num_whtlsts (RTE_PER_LCORE(num_whtlsts)) +#define DPVS_WHTLST_IPSET_TAB_BITS 8 +#define DPVS_WHTLST_IPSET_TAB_SIZE (1 << DPVS_WHTLST_IPSET_TAB_BITS) +#define DPVS_WHTLST_IPSET_TAB_MASK (DPVS_WHTLST_IPSET_TAB_SIZE - 1) +#define this_whtlst_ipset_tab (RTE_PER_LCORE(dp_vs_whtlst_ipset_tab)) +#define this_num_whtlsts_ipset (RTE_PER_LCORE(num_whtlsts_ipset)) + static RTE_DEFINE_PER_LCORE(struct list_head *, dp_vs_whtlst_tab); -static RTE_DEFINE_PER_LCORE(rte_atomic32_t, num_whtlsts); +static RTE_DEFINE_PER_LCORE(uint32_t, num_whtlsts); + +static RTE_DEFINE_PER_LCORE(struct list_head *, dp_vs_whtlst_ipset_tab); +static RTE_DEFINE_PER_LCORE(uint32_t, num_whtlsts_ipset); static uint32_t dp_vs_whtlst_rnd; -static inline uint32_t whtlst_hashkey(const uint8_t proto, const union inet_addr *vaddr, const uint16_t vport) +static inline void whtlst_fill_conf(const struct whtlst_entry *entry, + struct dp_vs_whtlst_conf *conf) +{ + memset(conf, 0, sizeof(*conf)); + conf->vaddr = entry->vaddr; + conf->vport = entry->vport; + conf->proto = entry->proto; + conf->af = entry->af; + conf->subject = entry->subject; + if (entry->set) + strncpy(conf->ipset, entry->set->name, sizeof(conf->ipset) - 1); +} + +static inline uint32_t whtlst_hashkey(const union inet_addr *vaddr, + uint16_t vport, bool ipset) { /* jhash hurts performance, we do not use rte_jhash_2words here */ - return (((rte_be_to_cpu_16(proto) * 7 - + rte_be_to_cpu_32(vaddr->in.s_addr)) * 31 - + rte_be_to_cpu_16(vport)) * 15 - + dp_vs_whtlst_rnd) & DPVS_WHTLST_TAB_MASK; + if (ipset) + return ((((vaddr->in.s_addr * 31) ^ vport) * 131) + ^ dp_vs_whtlst_rnd) & DPVS_WHTLST_IPSET_TAB_MASK; + + return ((((vaddr->in.s_addr * 31) ^ vport) * 131) + ^ dp_vs_whtlst_rnd) & DPVS_WHTLST_TAB_MASK; } -struct whtlst_entry *dp_vs_whtlst_lookup(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *whtlst) +static inline struct whtlst_entry *dp_vs_whtlst_ip_lookup( + int af, uint8_t proto, const union inet_addr *vaddr, + uint16_t vport, const union inet_addr *subject) { unsigned hashkey; - struct whtlst_entry *whtlst_node; - - hashkey = whtlst_hashkey(proto, vaddr, vport); - list_for_each_entry(whtlst_node, &this_whtlst_tab[hashkey], list){ - if (whtlst_node->af == af && whtlst_node->proto == proto && - whtlst_node->vport == vport && - inet_addr_equal(af, &whtlst_node->vaddr, vaddr) && - inet_addr_equal(af, &whtlst_node->whtlst, whtlst)) - return whtlst_node; + struct whtlst_entry *entry; + + hashkey = whtlst_hashkey(vaddr, vport, false); + list_for_each_entry(entry, &this_whtlst_tab[hashkey], list){ + if (entry->af == af && entry->proto == proto && + entry->vport == vport && + inet_addr_equal(af, &entry->vaddr, vaddr) && + inet_addr_equal(af, &entry->subject, subject)) + return entry; } return NULL; } -bool dp_vs_whtlst_allow(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *whtlst) +static inline struct whtlst_entry *dp_vs_whtlst_ipset_lookup( + int af, uint8_t proto, const union inet_addr *vaddr, + uint16_t vport, const char *ipset) { unsigned hashkey; - struct whtlst_entry *whtlst_node; + struct whtlst_entry *entry; + + hashkey = whtlst_hashkey(vaddr, vport, true); + list_for_each_entry(entry, &this_whtlst_ipset_tab[hashkey], list) { + if (entry->af == af && entry->proto == proto && entry->vport == vport && + inet_addr_equal(af, &entry->vaddr, vaddr) && + !strncmp(entry->set->name, ipset, sizeof(entry->set->name))) + return entry; + } - hashkey = whtlst_hashkey(proto, vaddr, vport); + return NULL; +} + +static struct whtlst_entry *dp_vs_whtlst_lookup(const struct dp_vs_whtlst_conf *conf) +{ + struct whtlst_entry *entry; + + entry = dp_vs_whtlst_ip_lookup(conf->af, conf->proto, &conf->vaddr, conf->vport, + &conf->subject); + if (entry) + return entry; - if (&this_whtlst_tab[hashkey] == NULL || list_empty(&this_whtlst_tab[hashkey])) { - return true; + return dp_vs_whtlst_ipset_lookup(conf->af, conf->proto, &conf->vaddr, conf->vport, + conf->ipset); +} + +enum dpvs_whtlst_result { + DPVS_WHTLST_UNSET = 1, + DPVS_WHTLST_DENIED = 2, + DPVS_WHTLST_ALLOWED = 4, +}; + +static inline enum dpvs_whtlst_result dp_vs_whtlst_iplist_acl ( + int af, uint8_t proto, const union inet_addr *vaddr, + uint16_t vport, const union inet_addr *subject) +{ + bool set, hit; + unsigned hashkey; + struct whtlst_entry *entry; + + set = false; + hit = false; + + hashkey = whtlst_hashkey(vaddr, vport, false); + list_for_each_entry(entry, &this_whtlst_tab[hashkey], list){ + if (entry->af == af && entry->proto == proto && + entry->vport == vport && + inet_addr_equal(af, &entry->vaddr, vaddr)) { + set = true; + hit = inet_addr_equal(af, &entry->subject, subject); + if (hit) + break; + } } - list_for_each_entry(whtlst_node, &this_whtlst_tab[hashkey], list){ - if (whtlst_node->af == af && whtlst_node->proto == proto && - whtlst_node->vport == vport && - inet_addr_equal(af, &whtlst_node->vaddr, vaddr) && - inet_addr_equal(af, &whtlst_node->whtlst, whtlst)) - return true; + + if (!set) + return DPVS_WHTLST_UNSET; + if (hit) + return DPVS_WHTLST_ALLOWED; + return DPVS_WHTLST_DENIED; +} + +static enum dpvs_whtlst_result dp_vs_whtlst_ipset_acl(int af, uint8_t proto, + const union inet_addr *vaddr, uint16_t vport, struct rte_mbuf *mbuf) +{ + bool set, hit; + unsigned hashkey; + struct whtlst_entry *entry; + + set = false; + hit = false; + + hashkey = whtlst_hashkey(vaddr, vport, true); + list_for_each_entry(entry, &this_whtlst_ipset_tab[hashkey], list) { + if (entry->af == af && entry->proto == proto && + entry->vport == vport && + inet_addr_equal(af, &entry->vaddr, vaddr)) { + set = true; + rte_pktmbuf_prepend(mbuf, mbuf->l2_len); + hit = elem_in_set(entry->set, mbuf, entry->dst_match); + rte_pktmbuf_adj(mbuf, mbuf->l2_len); + if (hit) + break; + } } - return false; + if (!set) + return DPVS_WHTLST_UNSET; + if (hit) + return DPVS_WHTLST_ALLOWED; + return DPVS_WHTLST_DENIED; +} + +bool dp_vs_whtlst_filtered(int af, uint8_t proto, const union inet_addr *vaddr, + uint16_t vport, const union inet_addr *subject, struct rte_mbuf *mbuf) +{ + /* + * The tri-state combinations for ipset and iplist: + * ---------------------------------------------------- + * ipset\iplist | UNSET ALLOWED DENIED + * -------------|-------------------------------------- + * UNSET | Accept Accept Reject + * ALLOWED | Accept Accept Accept + * DENIED | Reject Accept Reject + * ---------------------------------------------------- + * + * Notes: + * - Once attached to service, the empty ipset whtlst entry denies all. + * The UNSET means no matched entries attached to the service. + * - If a client is allowed in either iplist or ipset, but denied in + * the other, then the client is allowed. + */ + enum dpvs_whtlst_result res1, res2; + + res1 = dp_vs_whtlst_iplist_acl(af, proto, vaddr, vport, subject); + res2 = dp_vs_whtlst_ipset_acl(af, proto, vaddr, vport, mbuf); + + return !((DPVS_WHTLST_ALLOWED == res1) || ( DPVS_WHTLST_ALLOWED == res2) + || ((DPVS_WHTLST_UNSET == res1) && (DPVS_WHTLST_UNSET == res2))); } -static int dp_vs_whtlst_add_lcore(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *whtlst) +static int dp_vs_whtlst_add_lcore(const struct dp_vs_whtlst_conf *conf) { unsigned hashkey; - struct whtlst_entry *new, *whtlst_node; - whtlst_node = dp_vs_whtlst_lookup(af, proto, vaddr, vport, whtlst); - if (whtlst_node) { + struct whtlst_entry *new; + bool is_ipset = conf->ipset[0] != '\0'; + + if (dp_vs_whtlst_lookup(conf)) return EDPVS_EXIST; - } - hashkey = whtlst_hashkey(proto, vaddr, vport); + hashkey = whtlst_hashkey(&conf->vaddr, conf->vport, is_ipset); new = rte_zmalloc("new_whtlst_entry", sizeof(struct whtlst_entry), 0); if (unlikely(new == NULL)) return EDPVS_NOMEM; - new->af = af; - new->vport = vport; - new->proto = proto; - memcpy(&new->vaddr, vaddr, sizeof(union inet_addr)); - memcpy(&new->whtlst, whtlst, sizeof(union inet_addr)); - list_add(&new->list, &this_whtlst_tab[hashkey]); - rte_atomic32_inc(&this_num_whtlsts); + new->vaddr = conf->vaddr; + new->vport = conf->vport; + new->proto = conf->proto; + new->af = conf->af; + + if (is_ipset) { + new->set = ipset_get(conf->ipset); + if (!new->set) { + RTE_LOG(ERR, SERVICE, "[%2d] %s: ipset %s not found\n", + rte_lcore_id(), __func__, conf->ipset); + rte_free(new); + return EDPVS_INVAL; + } + // Notes: Reassess it when new ipset types added! + if (!strcmp(new->set->type->name, "hash:ip,port,net") || + !strcmp(new->set->type->name, "hash:ip,port,ip") || + !strcmp(new->set->type->name, "hash:net,port,net")) + new->dst_match = true; + else + new->dst_match = false; + list_add(&new->list, &this_whtlst_ipset_tab[hashkey]); + ++this_num_whtlsts_ipset; + } else { + new->subject = conf->subject; + list_add(&new->list, &this_whtlst_tab[hashkey]); + ++this_num_whtlsts; + } return EDPVS_OK; } -static int dp_vs_whtlst_del_lcore(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *whtlst) +static int dp_vs_whtlst_del_lcore(const struct dp_vs_whtlst_conf *conf) { - struct whtlst_entry *whtlst_node; - - whtlst_node = dp_vs_whtlst_lookup(af, proto, vaddr, vport, whtlst); - if (whtlst_node != NULL) { - list_del(&whtlst_node->list); - rte_free(whtlst_node); - rte_atomic32_dec(&this_num_whtlsts); - return EDPVS_OK; + struct whtlst_entry *entry; + + entry = dp_vs_whtlst_lookup(conf); + if (!entry) + return EDPVS_NOTEXIST; + + if (entry->set) { /* ipset entry */ + list_del(&entry->list); + ipset_put(entry->set); + --this_num_whtlsts_ipset; + } else { + list_del(&entry->list); + --this_num_whtlsts; } - return EDPVS_NOTEXIST; + + rte_free(entry); + return EDPVS_OK; } static uint32_t whtlst_msg_seq(void) @@ -143,42 +297,33 @@ static uint32_t whtlst_msg_seq(void) return counter++; } -static int dp_vs_whtlst_add(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *whtlst) +static int dp_vs_whtlst_add(const struct dp_vs_whtlst_conf *conf) { lcoreid_t cid = rte_lcore_id(); int err; struct dpvs_msg *msg; - struct dp_vs_whtlst_conf cf; if (cid != rte_get_main_lcore()) { - RTE_LOG(INFO, SERVICE, "[%s] must set from master lcore\n", __func__); + RTE_LOG(INFO, SERVICE, "%s must set from master lcore\n", __func__); return EDPVS_NOTSUPP; } - memset(&cf, 0, sizeof(struct dp_vs_whtlst_conf)); - memcpy(&(cf.vaddr), vaddr, sizeof(union inet_addr)); - memcpy(&(cf.whtlst), whtlst, sizeof(union inet_addr)); - cf.af = af; - cf.vport = vport; - cf.proto = proto; - - /*set whtlst ip on master lcore*/ - err = dp_vs_whtlst_add_lcore(af, proto, vaddr, vport, whtlst); + /* master lcore */ + err = dp_vs_whtlst_add_lcore(conf); if (err && err != EDPVS_EXIST) { - RTE_LOG(ERR, SERVICE, "[%s] fail to set whtlst ip\n", __func__); + RTE_LOG(ERR, SERVICE, "%s: fail to add whtlst entry -- %s\n", __func__, dpvs_strerror(err)); return err; } - /*set whtlst ip on all slave lcores*/ + /* slave lcores */ msg = msg_make(MSG_TYPE_WHTLST_ADD, whtlst_msg_seq(), DPVS_MSG_MULTICAST, - cid, sizeof(struct dp_vs_whtlst_conf), &cf); + cid, sizeof(struct dp_vs_whtlst_conf), conf); if (!msg) return EDPVS_NOMEM; err = multicast_msg_send(msg, DPVS_MSG_F_ASYNC, NULL); if (err != EDPVS_OK) { msg_destroy(&msg); - RTE_LOG(INFO, SERVICE, "[%s] fail to send multicast message\n", __func__); + RTE_LOG(INFO, SERVICE, "%s: fail to send multicast message\n", __func__); return err; } msg_destroy(&msg); @@ -186,41 +331,33 @@ static int dp_vs_whtlst_add(int af, uint8_t proto, const union inet_addr *vaddr, return EDPVS_OK; } -static int dp_vs_whtlst_del(int af, uint8_t proto, const union inet_addr *vaddr, - uint16_t vport, const union inet_addr *whtlst) +static int dp_vs_whtlst_del(const struct dp_vs_whtlst_conf *conf) { lcoreid_t cid = rte_lcore_id(); int err; struct dpvs_msg *msg; - struct dp_vs_whtlst_conf cf; if (cid != rte_get_main_lcore()) { - RTE_LOG(INFO, SERVICE, "[%s] must set from master lcore\n", __func__); + RTE_LOG(INFO, SERVICE, "%s must set from master lcore\n", __func__); return EDPVS_NOTSUPP; } - memset(&cf, 0, sizeof(struct dp_vs_whtlst_conf)); - memcpy(&(cf.vaddr), vaddr, sizeof(union inet_addr)); - memcpy(&(cf.whtlst), whtlst, sizeof(union inet_addr)); - cf.af = af; - cf.vport = vport; - cf.proto = proto; - - /*del whtlst ip on master lcores*/ - err = dp_vs_whtlst_del_lcore(af, proto, vaddr, vport, whtlst); + /* master lcore */ + err = dp_vs_whtlst_del_lcore(conf); if (err) { + RTE_LOG(ERR, SERVICE, "%s: fail to del whtlst entry -- %s\n", __func__, dpvs_strerror(err)); return err; } - /*del whtlst ip on all slave lcores*/ + /* slave lcores */ msg = msg_make(MSG_TYPE_WHTLST_DEL, whtlst_msg_seq(), DPVS_MSG_MULTICAST, - cid, sizeof(struct dp_vs_whtlst_conf), &cf); + cid, sizeof(struct dp_vs_whtlst_conf), conf); if (!msg) return EDPVS_NOMEM; err = multicast_msg_send(msg, DPVS_MSG_F_ASYNC, NULL); if (err != EDPVS_OK) { msg_destroy(&msg); - RTE_LOG(INFO, SERVICE, "[%s] fail to send multicast message\n", __func__); + RTE_LOG(INFO, SERVICE, "%s: fail to send multicast message\n", __func__); return err; } msg_destroy(&msg); @@ -228,36 +365,56 @@ static int dp_vs_whtlst_del(int af, uint8_t proto, const union inet_addr *vaddr, return EDPVS_OK; } -void dp_vs_whtlst_flush(struct dp_vs_service *svc) +void dp_vs_whtlst_flush(struct dp_vs_service *svc) { - struct whtlst_entry *entry, *next; int hash; + struct whtlst_entry *entry, *next; + struct dp_vs_whtlst_conf conf; for (hash = 0; hash < DPVS_WHTLST_TAB_SIZE; hash++) { list_for_each_entry_safe(entry, next, &this_whtlst_tab[hash], list) { if (entry->af == svc->af - && entry->vport == svc->port - && entry->proto == svc->proto - && inet_addr_equal(svc->af, &entry->vaddr, &svc->addr)) - dp_vs_whtlst_del(svc->af, entry->proto, &entry->vaddr, - entry->vport, &entry->whtlst); + && entry->vport == svc->port + && entry->proto == svc->proto + && inet_addr_equal(svc->af, &entry->vaddr, &svc->addr)) { + whtlst_fill_conf(entry, &conf); + dp_vs_whtlst_del(&conf); + } + } + } + + for (hash = 0; hash < DPVS_WHTLST_IPSET_TAB_SIZE; hash++) { + list_for_each_entry_safe(entry, next, &this_whtlst_ipset_tab[hash], list) { + if (entry->af == svc->af + && entry->vport == svc->port + && entry->proto == svc->proto + && inet_addr_equal(svc->af, &entry->vaddr, &svc->addr)) { + whtlst_fill_conf(entry, &conf); + dp_vs_whtlst_del(&conf); + } } } - return; } static void dp_vs_whtlst_flush_all(void) { - struct whtlst_entry *entry, *next; int hash; + struct whtlst_entry *entry, *next; + struct dp_vs_whtlst_conf conf; for (hash = 0; hash < DPVS_WHTLST_TAB_SIZE; hash++) { list_for_each_entry_safe(entry, next, &this_whtlst_tab[hash], list) { - dp_vs_whtlst_del(entry->af, entry->proto, &entry->vaddr, - entry->vport, &entry->whtlst); + whtlst_fill_conf(entry, &conf); + dp_vs_whtlst_del(&conf); + } + } + + for (hash = 0; hash < DPVS_WHTLST_IPSET_TAB_SIZE; hash++) { + list_for_each_entry_safe(entry, next, &this_whtlst_ipset_tab[hash], list) { + whtlst_fill_conf(entry, &conf); + dp_vs_whtlst_del(&conf); } } - return; } /* @@ -265,40 +422,19 @@ static void dp_vs_whtlst_flush_all(void) */ static int whtlst_sockopt_set(sockoptid_t opt, const void *conf, size_t size) { - const struct dp_vs_whtlst_conf *whtlst_conf = conf; - int err; - - if (!conf && size < sizeof(*whtlst_conf)) + if (!conf && size < sizeof(struct dp_vs_whtlst_conf)) return EDPVS_INVAL; switch (opt) { case SOCKOPT_SET_WHTLST_ADD: - err = dp_vs_whtlst_add(whtlst_conf->af, - whtlst_conf->proto, &whtlst_conf->vaddr, - whtlst_conf->vport, &whtlst_conf->whtlst); - break; + return dp_vs_whtlst_add(conf); case SOCKOPT_SET_WHTLST_DEL: - err = dp_vs_whtlst_del(whtlst_conf->af, - whtlst_conf->proto, &whtlst_conf->vaddr, - whtlst_conf->vport, &whtlst_conf->whtlst); - break; + return dp_vs_whtlst_del(conf); default: - err = EDPVS_NOTSUPP; - break; + return EDPVS_NOTSUPP; } - return err; -} - -static void whtlst_fill_conf(struct dp_vs_whtlst_conf *cf, - const struct whtlst_entry *entry) -{ - memset(cf, 0 ,sizeof(*cf)); - cf->af = entry->af; - cf->vaddr = entry->vaddr; - cf->whtlst = entry->whtlst; - cf->proto = entry->proto; - cf->vport = entry->vport; + return EDPVS_OK; } static int whtlst_sockopt_get(sockoptid_t opt, const void *conf, size_t size, @@ -309,7 +445,7 @@ static int whtlst_sockopt_get(sockoptid_t opt, const void *conf, size_t size, size_t naddr, hash; int off = 0; - naddr = rte_atomic32_read(&this_num_whtlsts); + naddr = this_num_whtlsts + this_num_whtlsts_ipset; *outsize = sizeof(struct dp_vs_whtlst_conf_array) + naddr * sizeof(struct dp_vs_whtlst_conf); *out = rte_calloc(NULL, 1, *outsize, 0); @@ -322,7 +458,15 @@ static int whtlst_sockopt_get(sockoptid_t opt, const void *conf, size_t size, list_for_each_entry(entry, &this_whtlst_tab[hash], list) { if (off >= naddr) break; - whtlst_fill_conf(&array->whtlsts[off++], entry); + whtlst_fill_conf(entry, &array->whtlsts[off++]); + } + } + + for (hash = 0; hash < DPVS_WHTLST_IPSET_TAB_SIZE; hash++) { + list_for_each_entry(entry, &this_whtlst_ipset_tab[hash], list) { + if (off >= naddr) + break; + whtlst_fill_conf(entry, &array->whtlsts[off++]); } } @@ -332,35 +476,35 @@ static int whtlst_sockopt_get(sockoptid_t opt, const void *conf, size_t size, static int whtlst_msg_process(bool add, struct dpvs_msg *msg) { - struct dp_vs_whtlst_conf *cf; + struct dp_vs_whtlst_conf *conf; int err; assert(msg); if (msg->len != sizeof(struct dp_vs_whtlst_conf)) { - RTE_LOG(ERR, SERVICE, "%s: bad message.\n", __func__); + RTE_LOG(ERR, SERVICE, "%s: bad message\n", __func__); return EDPVS_INVAL; } - cf = (struct dp_vs_whtlst_conf *)msg->data; + conf = (struct dp_vs_whtlst_conf *)msg->data; if (add) { - err = dp_vs_whtlst_add_lcore(cf->af, cf->proto, &cf->vaddr, cf->vport, &cf->whtlst); - if (err && err != EDPVS_EXIST) { - RTE_LOG(ERR, SERVICE, "%s: fail to add whtlst: %s.\n", __func__, dpvs_strerror(err)); - } - } - else { - err = dp_vs_whtlst_del_lcore(cf->af, cf->proto, &cf->vaddr, cf->vport, &cf->whtlst); + err = dp_vs_whtlst_add_lcore(conf); + if (err && err != EDPVS_EXIST) + RTE_LOG(ERR, SERVICE, "%s: fail to add whtlst: %s\n", __func__, dpvs_strerror(err)); + } else { + err = dp_vs_whtlst_del_lcore(conf); + if (err && err != EDPVS_NOTEXIST) + RTE_LOG(ERR, SERVICE, "%s: fail to del whtlst: %s\n", __func__, dpvs_strerror(err)); } return err; } -inline static int whtlst_add_msg_cb(struct dpvs_msg *msg) +static inline int whtlst_add_msg_cb(struct dpvs_msg *msg) { return whtlst_msg_process(true, msg); } -inline static int whtlst_del_msg_cb(struct dpvs_msg *msg) +static inline int whtlst_del_msg_cb(struct dpvs_msg *msg) { return whtlst_msg_process(false, msg); } @@ -378,17 +522,29 @@ static struct dpvs_sockopts whtlst_sockopts = { static int whtlst_lcore_init(void *args) { int i; + if (!rte_lcore_is_enabled(rte_lcore_id())) return EDPVS_DISABLED; - this_whtlst_tab = rte_malloc(NULL, - sizeof(struct list_head) * DPVS_WHTLST_TAB_SIZE, - RTE_CACHE_LINE_SIZE); + + this_num_whtlsts = 0; + this_num_whtlsts_ipset = 0; + + this_whtlst_tab = rte_malloc(NULL, sizeof(struct list_head) * + DPVS_WHTLST_TAB_SIZE, RTE_CACHE_LINE_SIZE); if (!this_whtlst_tab) return EDPVS_NOMEM; - for (i = 0; i < DPVS_WHTLST_TAB_SIZE; i++) INIT_LIST_HEAD(&this_whtlst_tab[i]); + this_whtlst_ipset_tab = rte_malloc(NULL, sizeof(struct list_head) * + DPVS_WHTLST_IPSET_TAB_SIZE, RTE_CACHE_LINE_SIZE); + if (!this_whtlst_ipset_tab) { + rte_free(this_whtlst_tab); + return EDPVS_NOMEM; + } + for (i = 0; i < DPVS_WHTLST_IPSET_TAB_SIZE; i++) + INIT_LIST_HEAD(&this_whtlst_ipset_tab[i]); + return EDPVS_OK; } @@ -403,13 +559,19 @@ static int whtlst_lcore_term(void *args) rte_free(this_whtlst_tab); this_whtlst_tab = NULL; } + + if (this_whtlst_ipset_tab) { + rte_free(this_whtlst_ipset_tab); + this_whtlst_ipset_tab = NULL; + } + return EDPVS_OK; } -static int whtlst_unregister_msg_cb(void) +static void whtlst_unregister_msg_cb(void) { - struct dpvs_msg_type msg_type; int err; + struct dpvs_msg_type msg_type; memset(&msg_type, 0, sizeof(struct dpvs_msg_type)); msg_type.type = MSG_TYPE_WHTLST_ADD; @@ -419,8 +581,8 @@ static int whtlst_unregister_msg_cb(void) msg_type.unicast_msg_cb = whtlst_add_msg_cb; err = msg_type_mc_unregister(&msg_type); if (err != EDPVS_OK) { - RTE_LOG(ERR, SERVICE, "%s: fail to unregister msg.\n", __func__); - return err; + RTE_LOG(WARNING, SERVICE, "%s: unregister WHTLST_ADD msg failed -- %s\n", + __func__, dpvs_strerror(err)); } memset(&msg_type, 0, sizeof(struct dpvs_msg_type)); @@ -431,10 +593,9 @@ static int whtlst_unregister_msg_cb(void) msg_type.unicast_msg_cb = whtlst_del_msg_cb; err = msg_type_mc_unregister(&msg_type); if (err != EDPVS_OK) { - RTE_LOG(ERR, SERVICE, "%s: fail to unregister msg.\n", __func__); - return err; + RTE_LOG(WARNING, SERVICE, "%s: unregister WHTLIST_DEL msg failed -- %s\n", + __func__, dpvs_strerror(err)); } - return EDPVS_OK; } int dp_vs_whtlst_init(void) @@ -443,13 +604,11 @@ int dp_vs_whtlst_init(void) lcoreid_t cid; struct dpvs_msg_type msg_type; - rte_atomic32_set(&this_num_whtlsts, 0); - rte_eal_mp_remote_launch(whtlst_lcore_init, NULL, CALL_MAIN); RTE_LCORE_FOREACH_WORKER(cid) { if ((err = rte_eal_wait_lcore(cid)) < 0) { - RTE_LOG(WARNING, SERVICE, "%s: lcore %d: %s.\n", - __func__, cid, dpvs_strerror(err)); + RTE_LOG(WARNING, SERVICE, "[%02d] %s: whtlst init failed -- %s\n", + cid, __func__, dpvs_strerror(err)); return err; } } @@ -462,7 +621,8 @@ int dp_vs_whtlst_init(void) msg_type.unicast_msg_cb = whtlst_add_msg_cb; err = msg_type_mc_register(&msg_type); if (err != EDPVS_OK) { - RTE_LOG(ERR, SERVICE, "%s: fail to register msg.\n", __func__); + RTE_LOG(ERR, SERVICE, "%s: register WHTLST_ADD msg failed -- %s\n", + __func__, dpvs_strerror(err)); return err; } @@ -474,14 +634,18 @@ int dp_vs_whtlst_init(void) msg_type.unicast_msg_cb = whtlst_del_msg_cb; err = msg_type_mc_register(&msg_type); if (err != EDPVS_OK) { - RTE_LOG(ERR, SERVICE, "%s: fail to register msg.\n", __func__); + RTE_LOG(ERR, SERVICE, "%s: register WHTLST_DEL msg failed -- %s\n", + __func__, dpvs_strerror(err)); return err; } if ((err = sockopt_register(&whtlst_sockopts)) != EDPVS_OK) { + RTE_LOG(ERR, SERVICE, "%s: register sockopts failed -- %s\n", + __func__, dpvs_strerror(err)); whtlst_unregister_msg_cb(); return err; } + dp_vs_whtlst_rnd = (uint32_t)random(); return EDPVS_OK; @@ -492,17 +656,18 @@ int dp_vs_whtlst_term(void) int err; lcoreid_t cid; - if ((err = whtlst_unregister_msg_cb()) != EDPVS_OK) - return err; + if ((err = sockopt_unregister(&whtlst_sockopts)) != EDPVS_OK) { + RTE_LOG(WARNING, SERVICE, "%s: unregister sockopts failed -- %s\n", + __func__, dpvs_strerror(err)); + } - if ((err = sockopt_unregister(&whtlst_sockopts)) != EDPVS_OK) - return err; + whtlst_unregister_msg_cb(); rte_eal_mp_remote_launch(whtlst_lcore_term, NULL, CALL_MAIN); RTE_LCORE_FOREACH_WORKER(cid) { if ((err = rte_eal_wait_lcore(cid)) < 0) { - RTE_LOG(WARNING, SERVICE, "%s: lcore %d: %s.\n", - __func__, cid, dpvs_strerror(err)); + RTE_LOG(WARNING, SERVICE, "[%02d] %s: whtlst termination failed -- %s\n", + cid, __func__, dpvs_strerror(err)); } } diff --git a/test/ipset/dpvs-agent.sh b/test/ipset/dpvs-agent.sh new file mode 100755 index 000000000..8a22a82d0 --- /dev/null +++ b/test/ipset/dpvs-agent.sh @@ -0,0 +1,158 @@ +#!/bin/env sh +# + +## <> +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"bitmap:ip,mac","Name":"ttt","CreationOptions":{"Family":"ipv4","Comment":true,"Range":"192.168.88.0/24"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"bitmap:ip,mac","Name":"ttt","Entries":[{"Entry":"192.168.88.1,AA:bb:CC:11:22:33"},{"Entry":"192.168.88.100","Comment":"no mac","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"bitmap:ip,mac","Member":{"Entry":"192.168.88.1,AA:bb:CC:11:22:33"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"bitmap:ip,mac","Name":"ttt","Entries":[{"Entry":"192.168.88.100,AA:bb:CC:11:22:33"}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"bitmap:ip,mac","Name":"ttt","Entries":[{"Entry":"192.168.88.100","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +## <> + +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"bitmap:port","Name":"ttt","CreationOptions":{"Comment":true,"Range":"10000-20000"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"bitmap:port","Name":"ttt","Entries":[{"Entry":"tcp:10000-10002"},{"Entry":"tcp:10888","Comment":"single","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"bitmap:port","Member":{"Entry":"tcp:12222"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"bitmap:port","Name":"ttt","Entries":[{"Entry":"tcp:10000-10008"}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"bitmap:port","Name":"ttt","Entries":[{"Entry":"tcp:10003","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +## <> +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:ip","Name":"ttt","CreationOptions":{"Comment":true,"Family":"ipv4","HashSize": 128,"HashMaxElem": 10001}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip","Name":"ttt","Entries":[{"Entry":"192.168.88.100/30","Comment":"a cidr"},{"Entry":"10.64.68.1-10.64.68.3","Comment":"a range","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:ip","Member":{"Entry":"192.168.88.100"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip","Name":"ttt","Entries":[{"Entry":"192.168.88.100/30","Comment":"a cidr"},{"Entry":"10.64.68.10-10.64.68.14","Comment":"a range","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip","Name":"ttt","Entries":[{"Entry":"192.168.88.100-192.168.88.128","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:ip","Name":"ttt","CreationOptions":{"Comment":true,"Family":"ipv6","HashSize": 256,"HashMaxElem": 20001}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip","Name":"ttt","Entries":[{"Entry":"2001::B","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:ip","Member":{"Entry":"2001::a"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip","Name":"ttt","Entries":[{"Entry":"2001::b","Comment":"replace","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip","Name":"ttt","Entries":[{"Entry":"2001::a","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +## <> +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:net","Name":"ttt","CreationOptions":{"Comment":true,"Family":"ipv4"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net","Name":"ttt","Entries":[{"Entry":"192.168.88.128/26","Comment":"net1"},{"Entry":"10.64.0.10-10.64.0.20","Comment":"a net range","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:net","Member":{"Entry":"192.168.88.100"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net","Name":"ttt","Entries":[{"Entry":"192.168.88.128/26","Comment":"net1"},{"Entry":"192.168.88.164/30","Comment":"net1 nomatch","Options":{"NoMatch":true}},{"Entry":"10.64.0.10-10.64.0.20","Comment":"a net range","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net","Name":"ttt","Entries":[{"Entry":"192.168.88.192/28","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:net","Name":"ttt","CreationOptions":{"Comment":true,"Family":"ipv6"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net","Name":"ttt","Entries":[{"Entry":"2001::/64","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:net","Member":{"Entry":"2001::66"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net","Name":"ttt","Entries":[{"Entry":"2002::/64","Comment":"replace","Options":{"Force":false}},{"Entry":"2002::ff:0:0/96","Comment":"net1 nomatch","Options":{"NoMatch":true}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net","Name":"ttt","Entries":[{"Entry":"2002::/64","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +## <> +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:net,port","Name":"ttt","CreationOptions":{"Comment":true,"Family":"ipv4"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port","Name":"ttt","Entries":[{"Entry":"192.168.88.0/24,tcp:8080","Comment":"net cidr"},{"Entry":"10.64.0.10-10.64.0.20","Comment":"net range","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:net,port","Member":{"Entry":"192.168.88.100,tcp:8080"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port","Name":"ttt","Entries":[{"Entry":"192.168.88.128/26,udp:80-82","Comment":"net1"},{"Entry":"192.168.88.164/30,udp:80","Comment":"net1 nomatch","Options":{"NoMatch":true}},{"Entry":"10.64.0.10-10.64.0.20,tcp:6600","Comment":"a net range","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port","Name":"ttt","Entries":[{"Entry":"192.168.88.128/26,udp:81","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:net,port","Name":"ttt","CreationOptions":{"Comment":true,"Family":"ipv6"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port","Name":"ttt","Entries":[{"Entry":"2001::/64,tcp:8080-8083","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:net,port","Member":{"Entry":"2001::66,tcp:8082"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port","Name":"ttt","Entries":[{"Entry":"2002::/64,udp:80-83","Comment":"replace","Options":{"Force":false}},{"Entry":"2002::ff:0:0/96,udp:80","Comment":"net1 nomatch","Options":{"NoMatch":true}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port","Name":"ttt","Entries":[{"Entry":"2002::/64,udp:82","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +## <> +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:net,port,iface","Name":"ttt","CreationOptions":{"Comment":true,"Family":"ipv4"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,iface","Name":"ttt","Entries":[{"Entry":"192.168.88.0/24,tcp:8080,dpdk0","Comment":"net cidr"},{"Entry":"10.64.0.10-10.64.0.20,tcp:80-82,dpdk0","Comment":"net range","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:net,port,iface","Member":{"Entry":"192.168.88.100,tcp:8080,dpdk0"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,iface","Name":"ttt","Entries":[{"Entry":"192.168.88.0/24,tcp:80-82,dpdk0","Comment":"net cidr"},{"Entry":"10.64.0.10-10.64.0.20,tcp:8080,dpdk0","Comment":"net range","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,iface","Name":"ttt","Entries":[{"Entry":"192.168.88.0/24,tcp:81,dpdk0","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:net,port,iface","Name":"ttt","CreationOptions":{"Comment":false,"Family":"ipv6"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,iface","Name":"ttt","Entries":[{"Entry":"2001::/64,tcp:8080-8083,dpdk0","Options":{"Force":false}},{"Entry":"2002::/64,udp:6600,dpdk0","Comment":"xxxxx","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:net,port,iface","Member":{"Entry":"2001::66,tcp:8082,dpdk0"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,iface","Name":"ttt","Entries":[{"Entry":"2002::/64,udp:80-83,dpdk0","Comment":"zzzzz","Options":{"Force":false}},{"Entry":"2002::ff:0:0/96,udp:80,dpdk0","Comment":"net1 nomatch","Options":{"NoMatch":true}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,iface","Name":"ttt","Entries":[{"Entry":"2002::/64,udp:82,dpdk0","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +## <> +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,ip","Name":"ttt","CreationOptions":{"Comment":true,"Family":"ipv4"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,ip","Name":"ttt","Entries":[{"Entry":"192.168.1.16/31,tcp:8080-8081,192.168.2.100-192.168.2.102","Comment":"net-port-range"},{"Entry":"10.64.0.10-10.64.0.20,udp:6600,112.112.112.112","Comment":"udp","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,ip","Member":{"Entry":"192.168.1.17,tcp:8080,192.168.2.100"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,ip","Name":"ttt","Entries":[{"Entry":"192.168.1.16/31,tcp:8080-8081,192.168.2.100-192.168.2.102","Comment":"net-port-range"},{"Entry":"10.64.88.0,udp:6600,112.112.112.112","Comment":"udp","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,ip","Name":"ttt","Entries":[{"Entry":"192.1681.16/31,tcp:8081,192.168.2.101","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,ip","Name":"ttt","CreationOptions":{"Comment":false,"Family":"ipv6"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,ip","Name":"ttt","Entries":[{"Entry":"2001::4444,tcp:8080-8083,2002::7777","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,ip","Member":{"Entry":"2001::4444,tcp:8082,2002::7777"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,ip","Name":"ttt","Entries":[{"Entry":"2002::aaaa,udp:80-83,2001::6666","Comment":"xxxxx","Options":{"Force":false}},{"Entry":"2002::ff:1,tcp:80,2001::ee:2","Comment":"net1 nomatch","Options":{"NoMatch":true}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,ip","Name":"ttt","Entries":[{"Entry":"2002::aaaa,udp:82,2001::6666","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,ip","Name":"ttt","Entries":[{"Entry":"2002::aaaa,udp:80-83,2001::6666","Comment":"xxxxx","Options":{"Force":true}},{"Entry":"2002::ff:1,tcp:80,2001::ee:2","Comment":"net1 nomatch","Options":{"NoMatch":true}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +## <> +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,net","Name":"ttt"}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,net","Name":"ttt","Entries":[{"Entry":"192.168.1.5-192.168.1.6,tcp:8081-8082,192.168.88.0/24"},{"Entry":"10.64.100.100/30,udp:6600,10.64.200.0/24","Comment":"udp","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,net","Member":{"Entry":"192.168.1.6,tcp:8081,192.168.88.111"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,net","Name":"ttt","Entries":[{"Entry":"192.168.1.4/30,80,192.168.88.0/24"},{"Entry":"10.64.100.100/30,udp:6688,10.64.100.0/24","Comment":"udp","Options":{"Force":false}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,net","Name":"ttt","Entries":[{"Entry":"192.168.1.6/31,80,192.168.88.0/24"}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,net","Name":"ttt","CreationOptions":{"Comment":true,"Family":"ipv6","HashSize":64,"HashMaxElem":20000}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,net","Name":"ttt","Entries":[{"Entry":"2001::1,tcp:8080-8083,2002::0/64"},{"Entry":"2001::1,tcp:8080,2002::FFFF:0/112","Options":{"NoMatch":true}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,net","Member":{"Entry":"2001::1,tcp:8082,2002::FFFF:1"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,net","Name":"ttt","Entries":[{"Entry":"2001::1,tcp:8080-8083,2002::0/64"},{"Entry":"2001::1,tcp:8080,2001:FFFF::0/80","Comment":"replaced","Options":{"NoMatch":true}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:ip,port,net","Name":"ttt","Entries":[{"Entry":"2001::1,tcp:8080,2002::0/64"}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +## <> +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net","Name":"ttt"}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net","Name":"ttt","Entries":[{"Entry":"192.168.1.0/24,tcp:8080-8083,192.168.2.0/24"},{"Entry":"10.64.96.0/21,udp:6600,10.132.80.0/21","Comment":"udp","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net","Member":{"Entry":"192.168.1.4,tcp:8080,192.168.2.254"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net","Name":"ttt","Entries":[{"Entry":"192.168.1.0/24,tcp:8080-8083,192.168.2.0/24"},{"Entry":"10.64.96.0/21,udp:6600,10.132.80.0/21","Comment":"udp","Options":{"Force":false}},{"Entry":"10.64.97.0/24,udp:6600,10.132.82.0/24","Comment":"udp","Options":{"NoMatch":true}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net","Name":"ttt","Entries":[{"Entry":"192.168.1.0/24,tcp:8082,192.168.2.0/24"}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net","Name":"ttt","CreationOptions":{"Comment":true,"Family":"ipv6"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net","Name":"ttt","Entries":[{"Entry":"2001::/64,tcp:8080-8083,2002::0/64"},{"Entry":"2001::/120,tcp:8080,2002::FFFF:0/112","Options":{"NoMatch":true}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net","Member":{"Entry":"2001::1,tcp:8082,2002::FFFF:1"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net","Name":"ttt","Entries":[{"Entry":"2001::/64,tcp:8080-8083,2002::0/64"},{"Entry":"2001::/112,tcp:8080,2002::FFFF:0/112","Comment":"replaced","Options":{"NoMatch":true}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net","Name":"ttt","Entries":[{"Entry":"2001::/64,tcp:8081,2002::/64"}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +## <> +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net,port","Name":"ttt","CreationOptions":{"Comment":true}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net,port","Name":"ttt","Entries":[{"Entry":"192.168.1.0/24,tcp:8080-8083,192.168.2.0/24,tcp:12345"},{"Entry":"10.64.96.0/21,udp:53,10.132.80.0/21,udp:6600-6601","Comment":"udp","Options":{"Force":false}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net,port","Member":{"Entry":"192.168.1.4,tcp:8080,192.168.2.254,tcp:12345"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net,port","Name":"ttt","Entries":[{"Entry":"192.168.1.0/24,tcp:8080-8083,192.168.2.0/24,tcp:12345"},{"Entry":"10.64.96.0/21,udp:53,10.132.80.0/21,udp:6600-6601","Comment":"udp","Options":{"Force":false}},{"Entry":"10.64.96.0/24,udp:53,10.132.80.86/24,udp:6601","Comment":"add exceptions","Options":{"Nomatch":true}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net,port","Name":"ttt","Entries":[{"Entry":"10.64.96.0/21,udp:53,10.132.80.0/21,udp:6600-6601"}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt + +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net,port","Name":"ttt","CreationOptions":{"Family":"ipv6"}}' +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net,port","Name":"ttt","Entries":[{"Entry":"2001::/64,tcp:8080-8083,2002::0/64,tcp:80","Options":{"Force":true}},{"Entry":"2001::/120,tcp:8080,2002::FFFF:0/112,tcp:80","Options":{"NoMatch":true,"Force":true}}]}' +curl -X GET http://127.0.0.1:8866/v2/ipset/ttt | jq | more +curl -X POST http://127.0.0.1:8866/v2/ipset/ttt/cell -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net,port","Member":{"Entry":"2001::1,tcp:8082,2002::FFFF:1,tcp:80"}}' +curl -X PUT http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net,port","Name":"ttt","Entries":[{"Entry":"2001::/64,tcp:8080-8083,2002::0/64,tcp:80"},{"Entry":"2001::/112,tcp:8080,2002::FFFF:0/112,tcp:80","Comment":"replaced","Options":{"NoMatch":true}}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt/member -H "Content-Type: application/json" -d '{"Type":"hash:net,port,net,port","Name":"ttt","Entries":[{"Entry":"2001::/64,tcp:8082,2002::/64,tcp:80"}]}' +curl -X DELETE http://127.0.0.1:8866/v2/ipset/ttt diff --git a/tools/dpip/ipset.c b/tools/dpip/ipset.c index baeee9257..892b2374f 100644 --- a/tools/dpip/ipset.c +++ b/tools/dpip/ipset.c @@ -125,7 +125,7 @@ ipset_help(void) " MAC := 6 bytes MAC address string literal\n" " PORT := \"[{ tcp | udp | icmp | icmp6 }:]port1[-port2]\"\n" " OPTIONS := { comment | range NET | hashsize NUM | maxelem NUM }\n" - " ADTOPTS := { comment STRING | unmatch (for add only) }\n" + " ADTOPTS := { comment STRING | nomatch (for add only) }\n" " flag := { -F(--force) | { -4 | -6 } | -v }\n" "Examples:\n" " dpip ipset create foo bitmap:ip range 192.168.0.0/16 comment\n" @@ -147,7 +147,7 @@ static int addr_arg_parse(char *arg, struct inet_addr_range *range, uint8_t *cidr) { char *ip1, *ip2, *sep; - int *af = ¶m.option.family; + uint8_t *af = ¶m.option.family; /* ip/cidr */ if (cidr && (sep = strstr(arg, "/"))) { @@ -1081,7 +1081,11 @@ ipset_info_dump(struct ipset_info *info, bool sort) struct ipset_member *member; char header[HEADER_LEN], *members; - type = get_type_idx(); + type = get_type_idx_from_type(info->type); + if (type < 0) { + fprintf(stderr, "unsupported ipset type %s\n", info->type); + return; + } /* header */ types[type].dump_header(header, info); @@ -1099,7 +1103,7 @@ ipset_info_dump(struct ipset_info *info, bool sort) struct ipset_member *members = (struct ipset_member*)info->members; sort_compare_func sort_compare = types[type].sort_compare; - for (i = 0; i < info->entries - 1; i++) { + for (i = 0; i + 1 < info->entries; i++) { min = i; for (j = i + 1; j < info->entries; j++) { if (sort_compare(info->af, &members[min], &members[j]) > 0) diff --git a/tools/dpvs-agent/cmd/dpvs-agent-server/api_init.go b/tools/dpvs-agent/cmd/dpvs-agent-server/api_init.go index 7912acbce..9fbb13937 100644 --- a/tools/dpvs-agent/cmd/dpvs-agent-server/api_init.go +++ b/tools/dpvs-agent/cmd/dpvs-agent-server/api_init.go @@ -25,9 +25,10 @@ import ( "time" "github.com/hashicorp/go-hclog" - "github.com/lestrrat-go/file-rotatelogs" + rotatelogs "github.com/lestrrat-go/file-rotatelogs" "github.com/dpvs-agent/cmd/device" + "github.com/dpvs-agent/cmd/ipset" "github.com/dpvs-agent/cmd/ipvs" "github.com/dpvs-agent/pkg/ipc/pool" "github.com/dpvs-agent/pkg/settings" @@ -187,6 +188,8 @@ func (agent *DpvsAgentServer) instantiateAPI(restAPI *operations.DpvsAgentAPI) { logger := hclog.Default().Named("main") + //////////////////////////////////// ipvs /////////////////////////////////////////// + // delete restAPI.VirtualserverDeleteVsVipPortHandler = ipvs.NewDelVsItem(cp, logger) restAPI.VirtualserverDeleteVsVipPortLaddrHandler = ipvs.NewDelVsLaddr(cp, logger) @@ -210,6 +213,8 @@ func (agent *DpvsAgentServer) instantiateAPI(restAPI *operations.DpvsAgentAPI) { // post restAPI.VirtualserverPostVsVipPortRsHandler = ipvs.NewPostVsRs(cp, logger) + //////////////////////////////////// device /////////////////////////////////////////// + // get // restAPI.DeviceGetDeviceNameAddrHandler // restAPI.DeviceGetDeviceNameRouteHandler @@ -230,6 +235,24 @@ func (agent *DpvsAgentServer) instantiateAPI(restAPI *operations.DpvsAgentAPI) { restAPI.DeviceDeleteDeviceNameVlanHandler = device.NewDelDeviceVlan(cp, logger) restAPI.DeviceDeleteDeviceNameNetlinkAddrHandler = device.NewDelDeviceNetlinkAddr(cp, logger) + //////////////////////////////////// ipset /////////////////////////////////////////// + + // GET + restAPI.IpsetGetHandler = ipset.NewIpsetGet(cp, logger) + restAPI.IpsetGetAllHandler = ipset.NewIpsetGetAll(cp, logger) + + // POST + restAPI.IpsetIsInHandler = ipset.NewIpsetIsIn(cp, logger) + restAPI.IpsetAddMemberHandler = ipset.NewIpsetAddMember(cp, logger) + + // PUT + restAPI.IpsetCreateHandler = ipset.NewIpsetCreate(cp, logger) + restAPI.IpsetReplaceMemberHandler = ipset.NewIpsetReplaceMember(cp, logger) + + // DELETE + restAPI.IpsetDestroyHandler = ipset.NewIpsetDestroy(cp, logger) + restAPI.IpsetDelMemberHandler = ipset.NewIpsetDelMember(cp, logger) + switch strings.ToLower(agent.InitMode) { case "network": case "local": diff --git a/tools/dpvs-agent/cmd/ipset/add_member.go b/tools/dpvs-agent/cmd/ipset/add_member.go new file mode 100644 index 000000000..71efaca51 --- /dev/null +++ b/tools/dpvs-agent/cmd/ipset/add_member.go @@ -0,0 +1,79 @@ +// Copyright 2023 IQiYi Inc. All Rights Reserved. +// +// 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 ipset + +import ( + "fmt" + + "github.com/dpvs-agent/pkg/ipc/pool" + "github.com/dpvs-agent/pkg/ipc/types" + api "github.com/dpvs-agent/restapi/operations/ipset" + "github.com/go-openapi/runtime/middleware" + "github.com/hashicorp/go-hclog" +) + +type ipsetAddMember struct { + connPool *pool.ConnPool + logger hclog.Logger +} + +func NewIpsetAddMember(cp *pool.ConnPool, parentLogger hclog.Logger) *ipsetAddMember { + logger := hclog.Default() + if parentLogger != nil { + logger = parentLogger.Named("ipsetAddMember") + } + return &ipsetAddMember{connPool: cp, logger: logger} +} + +func (h *ipsetAddMember) Handle(params api.AddMemberParams) middleware.Responder { + if params.IpsetParam == nil { + return api.NewAddMemberBadRequest().WithPayload("missing ipset param") + } + + if *params.IpsetParam.Name != params.Name { + return api.NewAddMemberBadRequest().WithPayload("ipset name mismatch") + } + + if params.IpsetParam.CreationOptions != nil { + return api.NewAddMemberBadRequest().WithPayload("CreationOptions set in adding member") + } + + conf := types.IPSetParamArray{} + if err := conf.Build(types.IPSET_OP_ADD, params.IpsetParam); err != nil { + return api.NewAddMemberBadRequest().WithPayload(fmt.Sprintf( + "build AddMember param failed: %s", err.Error())) + } + + if err := conf.Check(); err != nil { + return api.NewAddMemberBadRequest().WithPayload(fmt.Sprintf( + "AddMember params check failed: %s", err.Error())) + } + + err, derr := conf.AddDelMember(h.connPool, h.logger) + if derr == types.EDPVS_EXIST { + return api.NewAddMemberOK().WithPayload(fmt.Sprintf("%s (may partially succeed)", derr.String())) + } + if err != nil { + h.logger.Error("Ipset AddMember failed.", "setName", params.Name, "Reason", err.Error()) + if derr == types.EDPVS_NOTEXIST { + return api.NewAddMemberNotFound().WithPayload(derr.String()) + } + return api.NewAddMemberFailure().WithPayload(err.Error()) + } + + h.logger.Info("Ipset AddMember succeed.", "setName", params.Name) + return api.NewAddMemberCreated().WithPayload(fmt.Sprintf("ipset %s add members succeed", + params.Name)) +} diff --git a/tools/dpvs-agent/cmd/ipset/create.go b/tools/dpvs-agent/cmd/ipset/create.go new file mode 100644 index 000000000..5d5925872 --- /dev/null +++ b/tools/dpvs-agent/cmd/ipset/create.go @@ -0,0 +1,75 @@ +// Copyright 2023 IQiYi Inc. All Rights Reserved. +// +// 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 ipset + +import ( + "fmt" + + "github.com/dpvs-agent/pkg/ipc/pool" + "github.com/dpvs-agent/pkg/ipc/types" + api "github.com/dpvs-agent/restapi/operations/ipset" + "github.com/go-openapi/runtime/middleware" + "github.com/hashicorp/go-hclog" +) + +type ipsetCreate struct { + connPool *pool.ConnPool + logger hclog.Logger +} + +func NewIpsetCreate(cp *pool.ConnPool, parentLogger hclog.Logger) *ipsetCreate { + logger := hclog.Default() + if parentLogger != nil { + logger = parentLogger.Named("ipsetCreate") + } + return &ipsetCreate{connPool: cp, logger: logger} +} + +func (h *ipsetCreate) Handle(params api.CreateParams) middleware.Responder { + if params.IpsetParam == nil { + return api.NewCreateBadRequest().WithPayload("missing ipset param") + } + + if *params.IpsetParam.Name != params.Name { + return api.NewCreateBadRequest().WithPayload("ipset name mismatch") + } + + conf := types.IPSetParam{} + conf.SetOpcode(types.IPSET_OP_CREATE) + if err := conf.Build(params.IpsetParam); err != nil { + return api.NewCreateBadRequest().WithPayload(fmt.Sprintf( + "build create param failed: %s", err.Error())) + } + + if err := conf.Check(); err != nil { + return api.NewCreateBadRequest().WithPayload(fmt.Sprintf("invalid create params: %s", + err.Error())) + } + + err, derr := conf.CreateDestroy(h.connPool, h.logger) + if derr == types.EDPVS_EXIST { + return api.NewCreateOK().WithPayload(derr.String()) + } + if err != nil { + h.logger.Error("Ipset Create failed.", "setName", params.Name, "Reason", err.Error()) + if derr == types.EDPVS_NOTEXIST { + return api.NewCreateNotFound().WithPayload(derr.String()) + } + return api.NewCreateFailure().WithPayload(err.Error()) + } + + h.logger.Info("Ipset Create succeed.", "setName", params.Name) + return api.NewCreateCreated().WithPayload(fmt.Sprintf("ipset %s created", params.Name)) +} diff --git a/tools/dpvs-agent/cmd/ipset/del_member.go b/tools/dpvs-agent/cmd/ipset/del_member.go new file mode 100644 index 000000000..fa2a8532c --- /dev/null +++ b/tools/dpvs-agent/cmd/ipset/del_member.go @@ -0,0 +1,77 @@ +// Copyright 2023 IQiYi Inc. All Rights Reserved. +// +// 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 ipset + +import ( + "fmt" + + "github.com/dpvs-agent/pkg/ipc/pool" + "github.com/dpvs-agent/pkg/ipc/types" + api "github.com/dpvs-agent/restapi/operations/ipset" + "github.com/go-openapi/runtime/middleware" + "github.com/hashicorp/go-hclog" +) + +type ipsetDelMember struct { + connPool *pool.ConnPool + logger hclog.Logger +} + +func NewIpsetDelMember(cp *pool.ConnPool, parentLogger hclog.Logger) *ipsetDelMember { + logger := hclog.Default() + if parentLogger != nil { + logger = parentLogger.Named("ipsetDelMember") + } + return &ipsetDelMember{connPool: cp, logger: logger} +} + +func (h *ipsetDelMember) Handle(params api.DelMemberParams) middleware.Responder { + if params.IpsetParam == nil { + return api.NewDelMemberBadRequest().WithPayload("missing ipset param") + } + + if *params.IpsetParam.Name != params.Name { + return api.NewDelMemberBadRequest().WithPayload("ipset name mismatch") + } + + if params.IpsetParam.CreationOptions != nil { + return api.NewDelMemberBadRequest().WithPayload("CreationOptions set in deleting member") + } + + conf := types.IPSetParamArray{} + if err := conf.Build(types.IPSET_OP_DEL, params.IpsetParam); err != nil { + return api.NewDelMemberBadRequest().WithPayload(fmt.Sprintf( + "build DelMember param failed: %s", err.Error())) + } + + if err := conf.Check(); err != nil { + return api.NewDelMemberBadRequest().WithPayload(fmt.Sprintf( + "DelMember params check failed: %s", err.Error())) + } + + err, derr := conf.AddDelMember(h.connPool, h.logger) + if derr == types.EDPVS_NOTEXIST { + return api.NewDelMemberNotFound().WithPayload(fmt.Sprintf("%s(may partially deleted)", + derr.String())) + } + if err != nil { + h.logger.Error("Ipset DelMember failed.", "setName", params.Name, "Reason", err.Error()) + return api.NewDelMemberFailure().WithPayload(err.Error()) + } + + h.logger.Info("Ipset DelMember succeed.", "setName", params.Name) + return api.NewDelMemberOK().WithPayload(fmt.Sprintf("ipset %s delete members succeed", + params.Name)) +} diff --git a/tools/dpvs-agent/cmd/ipset/destroy.go b/tools/dpvs-agent/cmd/ipset/destroy.go new file mode 100644 index 000000000..b44e1d53e --- /dev/null +++ b/tools/dpvs-agent/cmd/ipset/destroy.go @@ -0,0 +1,56 @@ +// Copyright 2023 IQiYi Inc. All Rights Reserved. +// +// 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 ipset + +import ( + "fmt" + + "github.com/dpvs-agent/pkg/ipc/pool" + "github.com/dpvs-agent/pkg/ipc/types" + api "github.com/dpvs-agent/restapi/operations/ipset" + "github.com/go-openapi/runtime/middleware" + "github.com/hashicorp/go-hclog" +) + +type ipsetDestroy struct { + connPool *pool.ConnPool + logger hclog.Logger +} + +func NewIpsetDestroy(cp *pool.ConnPool, parentLogger hclog.Logger) *ipsetDestroy { + logger := hclog.Default() + if parentLogger != nil { + logger = parentLogger.Named("ipsetDestroy") + } + return &ipsetDestroy{connPool: cp, logger: logger} +} + +func (h *ipsetDestroy) Handle(params api.DestroyParams) middleware.Responder { + conf := types.IPSetParam{} + conf.SetOpcode(types.IPSET_OP_DESTROY) + conf.SetName(params.Name) + + err, derr := conf.CreateDestroy(h.connPool, h.logger) + if derr == types.EDPVS_NOTEXIST { + return api.NewDestroyNotFound().WithPayload(derr.String()) + } + if err != nil { + h.logger.Error("Ipset Destroy failed.", "setName", params.Name, "Reason", err.Error()) + return api.NewDestroyFailure().WithPayload(err.Error()) + } + + h.logger.Info("Ipset Destroy succeed.", "setName", params.Name) + return api.NewDestroyOK().WithPayload(fmt.Sprintf("ipset %s destroyed", params.Name)) +} diff --git a/tools/dpvs-agent/cmd/ipset/get.go b/tools/dpvs-agent/cmd/ipset/get.go new file mode 100644 index 000000000..998321e52 --- /dev/null +++ b/tools/dpvs-agent/cmd/ipset/get.go @@ -0,0 +1,63 @@ +// Copyright 2023 IQiYi Inc. All Rights Reserved. +// +// 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 ipset + +import ( + "github.com/dpvs-agent/pkg/ipc/pool" + "github.com/dpvs-agent/pkg/ipc/types" + api "github.com/dpvs-agent/restapi/operations/ipset" + "github.com/go-openapi/runtime/middleware" + "github.com/hashicorp/go-hclog" +) + +type ipsetGet struct { + connPool *pool.ConnPool + logger hclog.Logger +} + +func NewIpsetGet(cp *pool.ConnPool, parentLogger hclog.Logger) *ipsetGet { + logger := hclog.Default() + if parentLogger != nil { + logger = parentLogger.Named("ipsetGet") + } + return &ipsetGet{connPool: cp, logger: logger} +} + +func (h *ipsetGet) Handle(params api.GetParams) middleware.Responder { + conf := &types.IPSetParam{} + + conf.SetOpcode(types.IPSET_OP_LIST) + conf.SetName(params.Name) + infos, err, derr := conf.Get(h.connPool, h.logger) + if err != nil { + h.logger.Error("Ipset Get failed.", "setName", params.Name, "Reason", err.Error()) + if derr == types.EDPVS_NOTEXIST { + return api.NewGetNotFound().WithPayload(derr.String()) + } + return api.NewGetFailure().WithPayload(err.Error()) + } + + h.logger.Info("Ipset Get succeed", "setName", params.Name) + model, err := infos.Model() + if err != nil { + h.logger.Error("Modelling ipset Get result failed.", "setName", params.Name, "Reason", err.Error()) + } + + resp := api.NewGetOK() + if model.Count > 0 { + resp.SetPayload(model.Infos[0]) + } + return resp +} diff --git a/tools/dpvs-agent/cmd/ipset/get_all.go b/tools/dpvs-agent/cmd/ipset/get_all.go new file mode 100644 index 000000000..2e654e92e --- /dev/null +++ b/tools/dpvs-agent/cmd/ipset/get_all.go @@ -0,0 +1,54 @@ +// Copyright 2023 IQiYi Inc. All Rights Reserved. +// +// 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 ipset + +import ( + "github.com/dpvs-agent/pkg/ipc/pool" + "github.com/dpvs-agent/pkg/ipc/types" + api "github.com/dpvs-agent/restapi/operations/ipset" + "github.com/go-openapi/runtime/middleware" + "github.com/hashicorp/go-hclog" +) + +type ipsetGetAll struct { + connPool *pool.ConnPool + logger hclog.Logger +} + +func NewIpsetGetAll(cp *pool.ConnPool, parentLogger hclog.Logger) *ipsetGetAll { + logger := hclog.Default() + if parentLogger != nil { + logger = parentLogger.Named("ipsetGetAll") + } + return &ipsetGetAll{connPool: cp, logger: logger} +} + +func (h *ipsetGetAll) Handle(params api.GetAllParams) middleware.Responder { + conf := &types.IPSetParam{} + + conf.SetOpcode(types.IPSET_OP_LIST) + infos, err, _ := conf.Get(h.connPool, h.logger) + if err != nil { + h.logger.Error("Ipset GetAll failed.", "Reason", err.Error()) + return api.NewGetAllFailure().WithPayload(err.Error()) + } + + h.logger.Info("Ipset GetAll succeed") + model, err := infos.Model() + if err != nil { + h.logger.Error("Modelling ipset GetAll result failed.", "Reason", err.Error()) + } + return api.NewGetAllOK().WithPayload(model) +} diff --git a/tools/dpvs-agent/cmd/ipset/is_in.go b/tools/dpvs-agent/cmd/ipset/is_in.go new file mode 100644 index 000000000..eadd3f1f2 --- /dev/null +++ b/tools/dpvs-agent/cmd/ipset/is_in.go @@ -0,0 +1,81 @@ +// Copyright 2023 IQiYi Inc. All Rights Reserved. +// +// 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 ipset + +import ( + "fmt" + + "github.com/dpvs-agent/pkg/ipc/pool" + "github.com/dpvs-agent/pkg/ipc/types" + api "github.com/dpvs-agent/restapi/operations/ipset" + "github.com/go-openapi/runtime/middleware" + "github.com/hashicorp/go-hclog" +) + +type ipsetIsIn struct { + connPool *pool.ConnPool + logger hclog.Logger +} + +func NewIpsetIsIn(cp *pool.ConnPool, parentLogger hclog.Logger) *ipsetIsIn { + logger := hclog.Default() + if parentLogger != nil { + logger = parentLogger.Named("ipsetIsIn") + } + return &ipsetIsIn{connPool: cp, logger: logger} +} + +func (h *ipsetIsIn) Handle(params api.IsInParams) middleware.Responder { + if params.IpsetCell == nil { + return api.NewIsInBadRequest().WithPayload("missing ipset entry") + } + + conf := types.IPSetParam{} + conf.SetOpcode(types.IPSET_OP_TEST) + conf.SetName(params.Name) + conf.SetKind(string(*params.IpsetCell.Type)) + if err := conf.BuildMember(params.IpsetCell.Member); err != nil { + return api.NewIsInBadRequest().WithPayload(fmt.Sprintf("invalid member: %s", err.Error())) + } + + if err := conf.Check(); err != nil { + return api.NewIsInBadRequest().WithPayload(fmt.Sprintf("invalid param: %s", err.Error())) + } + + result, err, derr := conf.IsIn(h.connPool, h.logger) + if err != nil { + h.logger.Error("Ipset IsIn failed.", "setName", params.Name, "Reason", err.Error()) + if derr == types.EDPVS_NOTEXIST { + return api.NewIsInNotFound().WithPayload(derr.String()) + } + return api.NewIsInFailure().WithPayload(err.Error()) + } + h.logger.Info("Ipset InIn succeed.", "setName", params.Name) + + nomatch := "" + if params.IpsetCell.Member.Options != nil && + params.IpsetCell.Member.Options.NoMatch != nil && + *params.IpsetCell.Member.Options.NoMatch { + nomatch = " (nomatch)" + } + + msg := "" + if result { + msg = fmt.Sprintf("%s%s is IN set %s", nomatch, *params.IpsetCell.Member.Entry, params.Name) + } else { + msg = fmt.Sprintf("%s%s is NOT IN set %s", nomatch, *params.IpsetCell.Member.Entry, params.Name) + } + return api.NewIsInOK().WithPayload(&api.IsInOKBody{Result: &result, Message: msg}) +} diff --git a/tools/dpvs-agent/cmd/ipset/replace_member.go b/tools/dpvs-agent/cmd/ipset/replace_member.go new file mode 100644 index 000000000..73b6c5156 --- /dev/null +++ b/tools/dpvs-agent/cmd/ipset/replace_member.go @@ -0,0 +1,81 @@ +// Copyright 2023 IQiYi Inc. All Rights Reserved. +// +// 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 ipset + +import ( + "fmt" + + "github.com/dpvs-agent/pkg/ipc/pool" + "github.com/dpvs-agent/pkg/ipc/types" + api "github.com/dpvs-agent/restapi/operations/ipset" + "github.com/go-openapi/runtime/middleware" + "github.com/hashicorp/go-hclog" +) + +type ipsetReplaceMember struct { + connPool *pool.ConnPool + logger hclog.Logger +} + +func NewIpsetReplaceMember(cp *pool.ConnPool, parentLogger hclog.Logger) *ipsetReplaceMember { + logger := hclog.Default() + if parentLogger != nil { + logger = parentLogger.Named("ipsetReplaceMember") + } + return &ipsetReplaceMember{connPool: cp, logger: logger} +} + +func (h *ipsetReplaceMember) Handle(params api.ReplaceMemberParams) middleware.Responder { + if params.IpsetParam == nil { + return api.NewReplaceMemberBadRequest().WithPayload("missing ipset param") + } + + if *params.IpsetParam.Name != params.Name { + return api.NewReplaceMemberBadRequest().WithPayload("ipset name mismatch") + } + + if params.IpsetParam.CreationOptions != nil { + return api.NewReplaceMemberBadRequest().WithPayload("CreationOptions set in replacing member") + } + + opcode := types.IPSET_OP_FLUSH + if len(params.IpsetParam.Entries) > 0 { + opcode = types.IPSET_OP_ADD + } + + conf := types.IPSetParamArray{} + if err := conf.Build(opcode, params.IpsetParam); err != nil { + return api.NewReplaceMemberBadRequest().WithPayload(fmt.Sprintf( + "build ReplaceMember param failed: %s", err.Error())) + } + + if err := conf.Check(); err != nil { + return api.NewReplaceMemberBadRequest().WithPayload(fmt.Sprintf( + "ReplaceMember params check failed: %s", err.Error())) + } + + err, derr := conf.ReplaceMember(h.connPool, h.logger) + if derr == types.EDPVS_NOTEXIST { + return api.NewReplaceMemberNotFound().WithPayload(derr.String()) + } + if err != nil { + h.logger.Error("Ipset ReplaceMember failed.", "setName", params.Name, "Reason", err.Error()) + return api.NewReplaceMemberFailure().WithPayload(err.Error()) + } + + h.logger.Info("Ipset ReplaceMember succeed.", "setName", params.Name) + return api.NewReplaceMemberOK().WithPayload(fmt.Sprintf("ipset %s replace members succeed", + params.Name)) +} diff --git a/tools/dpvs-agent/cmd/ipvs/delete_vs_vip_port_allow.go b/tools/dpvs-agent/cmd/ipvs/delete_vs_vip_port_allow.go index f1e068e5d..ab04f776e 100644 --- a/tools/dpvs-agent/cmd/ipvs/delete_vs_vip_port_allow.go +++ b/tools/dpvs-agent/cmd/ipvs/delete_vs_vip_port_allow.go @@ -16,6 +16,7 @@ package ipvs import ( "net" + "strings" "github.com/dpvs-agent/pkg/ipc/pool" "github.com/dpvs-agent/pkg/ipc/types" @@ -48,18 +49,29 @@ func (h *delVsAllow) Handle(params apiVs.DeleteVsVipPortAllowParams) middleware. failed := false for _, allow := range params.ACL.Items { - if net.ParseIP(allow.Addr) == nil { - h.logger.Error("Invalid ip addr del.", "VipPort", params.VipPort, "Addr", allow.Addr) - return apiVs.NewDeleteVsVipPortAllowInvalidFrontend() + spec.SetCaddr("") + spec.SetIpset("") + if len(allow.Ipset) > 0 { + if !strings.HasPrefix(allow.Ipset, "ipset:") { + h.logger.Error("Invalid allow ipset format in del.", "VipPort", params.VipPort, + "Ipset", allow.Ipset, "expecting \"ipset:NAME\"") + return apiVs.NewPutVsVipPortAllowInvalidFrontend() + } + spec.SetIpset(allow.Ipset) + } else { + if net.ParseIP(allow.Addr) == nil { + h.logger.Error("Invalid ip addr del in del.", "VipPort", params.VipPort, "Addr", allow.Addr) + return apiVs.NewDeleteVsVipPortAllowInvalidFrontend() + } + spec.SetCaddr(allow.Addr) } - spec.SetSrc(allow.Addr) if result := spec.Del(h.connPool, false, h.logger); result != types.EDPVS_OK { failed = true h.logger.Error("IP Addr delete from white list failed.", "VipPort", params.VipPort, "Addr", allow.Addr, "result", result.String()) continue } - h.logger.Info("IP Addr delete from white list success.", "VipPort", params.VipPort, "Addr", allow.Addr) + h.logger.Info("Delete entry from black list success.", "VipPort", params.VipPort, "Addr", allow.Addr, "Ipset", allow.Ipset) } if failed { diff --git a/tools/dpvs-agent/cmd/ipvs/delete_vs_vip_port_deny.go b/tools/dpvs-agent/cmd/ipvs/delete_vs_vip_port_deny.go index 54d2bb9d2..f328056b2 100644 --- a/tools/dpvs-agent/cmd/ipvs/delete_vs_vip_port_deny.go +++ b/tools/dpvs-agent/cmd/ipvs/delete_vs_vip_port_deny.go @@ -16,6 +16,7 @@ package ipvs import ( "net" + "strings" "github.com/dpvs-agent/pkg/ipc/pool" "github.com/dpvs-agent/pkg/ipc/types" @@ -48,18 +49,29 @@ func (h *delVsDeny) Handle(params apiVs.DeleteVsVipPortDenyParams) middleware.Re failed := false for _, deny := range params.ACL.Items { - if net.ParseIP(deny.Addr) == nil { - h.logger.Error("Invalid ip addr del.", "VipPort", params.VipPort, "Addr", deny.Addr) - return apiVs.NewDeleteVsVipPortDenyInvalidFrontend() + spec.SetCaddr("") + spec.SetIpset("") + if len(deny.Ipset) > 0 { + if !strings.HasPrefix(deny.Ipset, "ipset:") { + h.logger.Error("Invalid deny ipset format in del.", "VipPort", params.VipPort, + "Ipset", deny.Ipset, "expecting \"ipset:NAME\"") + return apiVs.NewPutVsVipPortDenyInvalidFrontend() + } + spec.SetIpset(deny.Ipset) + } else { + if net.ParseIP(deny.Addr) == nil { + h.logger.Error("Invalid ip addr in del.", "VipPort", params.VipPort, "Addr", deny.Addr) + return apiVs.NewDeleteVsVipPortDenyInvalidFrontend() + } + spec.SetCaddr(deny.Addr) } - spec.SetSrc(deny.Addr) if result := spec.Del(h.connPool, true, h.logger); result != types.EDPVS_OK { h.logger.Error("IP Addr delete from black list failed.", "VipPort", params.VipPort, "Addr", deny.Addr, "result", result.String()) failed = true continue } - h.logger.Info("IP Addr delete from black list success.", "VipPort", params.VipPort, "Addr", deny.Addr) + h.logger.Info("Delete entry from black list success.", "VipPort", params.VipPort, "Addr", deny.Addr, "Ipset", deny.Ipset) } if failed { diff --git a/tools/dpvs-agent/cmd/ipvs/put_vs_vip_port_allow.go b/tools/dpvs-agent/cmd/ipvs/put_vs_vip_port_allow.go index a5ff5753a..5227b314b 100644 --- a/tools/dpvs-agent/cmd/ipvs/put_vs_vip_port_allow.go +++ b/tools/dpvs-agent/cmd/ipvs/put_vs_vip_port_allow.go @@ -17,6 +17,7 @@ package ipvs import ( // "fmt" "net" + "strings" // "github.com/dpvs-agent/models" "github.com/dpvs-agent/pkg/ipc/pool" @@ -50,18 +51,29 @@ func (h *putVsAllow) Handle(params apiVs.PutVsVipPortAllowParams) middleware.Res failed := false for _, allow := range params.ACL.Items { - if net.ParseIP(allow.Addr) == nil { - h.logger.Error("Invalid ip addr add.", "VipPort", params.VipPort, "Addr", allow.Addr) - return apiVs.NewPutVsVipPortAllowInvalidFrontend() + spec.SetCaddr("") + spec.SetIpset("") + if len(allow.Ipset) > 0 { + if !strings.HasPrefix(allow.Ipset, "ipset:") { + h.logger.Error("Invalid allow ipset format in add.", "VipPort", params.VipPort, + "Ipset", allow.Ipset, "expecting \"ipset:NAME\"") + return apiVs.NewPutVsVipPortAllowInvalidFrontend() + } + spec.SetIpset(allow.Ipset) + } else { + if net.ParseIP(allow.Addr) == nil { + h.logger.Error("Invalid ip addr add.", "VipPort", params.VipPort, "Addr", allow.Addr) + return apiVs.NewPutVsVipPortAllowInvalidFrontend() + } + spec.SetCaddr(allow.Addr) } - spec.SetSrc(allow.Addr) if result := spec.Add(h.connPool, false, h.logger); result != types.EDPVS_OK { failed = true h.logger.Error("Add ip addr to white list failed.", "VipPort", params.VipPort, "Addr", allow.Addr, "result", result.String()) continue } - h.logger.Info("Add ip addr to white list success.", "VipPort", params.VipPort, "Addr", allow.Addr) + h.logger.Info("Add entry to white list success.", "VipPort", params.VipPort, "Addr", allow.Addr, "Ipset", allow.Ipset) } if failed { diff --git a/tools/dpvs-agent/cmd/ipvs/put_vs_vip_port_deny.go b/tools/dpvs-agent/cmd/ipvs/put_vs_vip_port_deny.go index 632b563f6..5ff636871 100644 --- a/tools/dpvs-agent/cmd/ipvs/put_vs_vip_port_deny.go +++ b/tools/dpvs-agent/cmd/ipvs/put_vs_vip_port_deny.go @@ -17,6 +17,7 @@ package ipvs import ( // "fmt" "net" + "strings" // "github.com/dpvs-agent/models" "github.com/dpvs-agent/pkg/ipc/pool" @@ -50,18 +51,29 @@ func (h *putVsDeny) Handle(params apiVs.PutVsVipPortDenyParams) middleware.Respo failed := false for _, deny := range params.ACL.Items { - if net.ParseIP(deny.Addr) == nil { - h.logger.Error("Invalid ip addr add.", "VipPort", params.VipPort, "Addr", deny.Addr) - return apiVs.NewPutVsVipPortDenyInvalidFrontend() + spec.SetCaddr("") + spec.SetIpset("") + if len(deny.Ipset) > 0 { + if !strings.HasPrefix(deny.Ipset, "ipset:") { + h.logger.Error("Invalid deny ipset format in add.", "VipPort", params.VipPort, + "Ipset", deny.Ipset, "expecting \"ipset:NAME\"") + return apiVs.NewPutVsVipPortDenyInvalidFrontend() + } + spec.SetIpset(deny.Ipset) + } else { + if net.ParseIP(deny.Addr) == nil { + h.logger.Error("Invalid deny ip addr in add.", "VipPort", params.VipPort, "Addr", deny.Addr) + return apiVs.NewPutVsVipPortDenyInvalidFrontend() + } + spec.SetCaddr(deny.Addr) } - spec.SetSrc(deny.Addr) if result := spec.Add(h.connPool, true, h.logger); result != types.EDPVS_OK { h.logger.Error("Add ip addr to black list failed.", "VipPort", params.VipPort, "Addr", deny.Addr, "result", result.String()) failed = true continue } - h.logger.Info("Add ip addr to black list success.", "VipPort", params.VipPort, "Addr", deny.Addr) + h.logger.Info("Add entry to black list success.", "VipPort", params.VipPort, "Addr", deny.Addr, "Ipset", deny.Ipset) } if failed { diff --git a/tools/dpvs-agent/dpvs-agent-api.yaml b/tools/dpvs-agent/dpvs-agent-api.yaml index 8840cdafd..3e7653519 100644 --- a/tools/dpvs-agent/dpvs-agent-api.yaml +++ b/tools/dpvs-agent/dpvs-agent-api.yaml @@ -11,33 +11,35 @@ # 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. - +--- swagger: "2.0" -info: +info: description: "dpvs agent api" version: "1.0.0" title: "dpvs agent" host: "petstore.swagger.io" basePath: "/v2" tags: -- name: "virtualserver" - description: "virtualserver" -- name: "route" - description: "route" -- name: "laddr" - description: "laddr" -- name: "tunnel" - description: "tunnel" -- name: "inetaddr" - description: "inet addr" -- name: "white_list" - description: "white list" -- name: "black_list" - description: "black list" -- name: "arp" - description: "arp" + - name: "virtualserver" + description: "virtualserver" + - name: "route" + description: "route" + - name: "laddr" + description: "laddr" + - name: "tunnel" + description: "tunnel" + - name: "inetaddr" + description: "inet addr" + - name: "white_list" + description: "white list" + - name: "black_list" + description: "black list" + - name: "arp" + description: "arp" + - name: "ipset" + description: "ipset" schemes: -- "http" + - "http" parameters: service-id: name: VipPort @@ -129,9 +131,9 @@ parameters: in: query type: string enum: - - unset - - on - - off + - unset + - on + - off default: unset required: false link: @@ -139,9 +141,9 @@ parameters: in: query type: string enum: - - unset - - up - - down + - unset + - up + - down default: unset required: false forward2kni: @@ -149,9 +151,9 @@ parameters: in: query type: string enum: - - unset - - on - - off + - unset + - on + - off default: unset required: false version: @@ -159,6 +161,21 @@ parameters: in: query type: string required: true + ipset-name: + name: name + in: path + type: string + required: true + ipset-param: + name: ipsetParam + in: body + schema: + $ref: "#/definitions/IpsetInfo" + ipset-cell: + name: ipsetCell + in: body + schema: + $ref: "#/definitions/IpsetCell" definitions: NodeServiceSnapshot: type: object @@ -185,6 +202,8 @@ definitions: properties: addr: type: string + ipset: + type: string InetAddrSpec: properties: addr: @@ -281,7 +300,7 @@ definitions: properties: Spec: "$ref": "#/definitions/RealServerSpecTiny" - Stats: + Stats: "$ref": "#/definitions/ServerStats" RealServerSpecTiny: type: object @@ -324,9 +343,6 @@ definitions: "$ref": "#/definitions/NicDeviceDetail" stats: "$ref": "#/definitions/NicDeviceStats" - #extra: - # "$ref": "#/definitions/NicDeviceStats" - #NicDeviceExtra: padding NicDeviceDetail: type: object properties: @@ -439,10 +455,10 @@ definitions: type: string description: State the component is in enum: - - Ok - - Warning - - Failure - - Disabled + - Ok + - Warning + - Failure + - Disabled msg: type: string description: Human readable status/error/warning message @@ -482,7 +498,7 @@ definitions: AddrRange: type: "object" properties: - Start: + Start: type: "string" End: type: "string" @@ -640,11 +656,148 @@ definitions: - conhash Match: "$ref": "#/definitions/MatchSpec" + IpsetOption: + description: IpsetOption defines common options for ipset operations. + type: object + properties: + NoMatch: + description: > + Nomatch excludes a small element range from an ipset, + which is mainly used by network-cidr based ipset. + type: boolean + default: false + Force: + description: > + When add members to ipset with Force set, the already existing members + are replaced sliently instead of emitting an EDPVS_EXIST error; When delete + non-existent memebers from ipset, the DPSVS_NOTEXIST error is ignored. + type: boolean + default: false + IpsetCreationOption: + description: > + IpsetCreationOption contains all available options required + in creating an ipset. + properties: + Family: + type: string + enum: + - ipv4 + - ipv6 + Comment: + type: boolean + default: false + HashSize: + type: integer + format: uint32 + HashMaxElem: + type: integer + format: uint32 + Range: + description: | + vaild format: ipv4-ipv4, ipv4/pfx, ipv6/pfx, port-port + type: string + IpsetType: + type: string + enum: + - bitmap:ip + - bitmap:ip,mac + - bitmap:port + - hash:ip + - hash:net + - hash:ip,port + - hash:net,port + - hash:net,port,iface + - hash:ip,port,ip + - hash:ip,port,net + - hash:net,port,net + - hash:net,port,net,port + IpsetMember: + description: IpsetMember represents a specific entry in ipset. + type: object + required: + - Entry + properties: + Entry: + description: | + type specific entry data, for example + * 192.168.1.0/29 (bitmap:ip) + * 192.168.88.0/24,tcp:8080-8082 (hash:net) + * 2001::1,8080-8082,2002::aaaa:bbbb:ccc0:0/108 (hash:ip,port,net) + type: string + Comment: + type: string + minLength: 1 + maxLength: 32 # IPSET_MAXCOMLEN = 32 + Options: + $ref: "#/definitions/IpsetOption" + IpsetCell: + description: IpsetCell represents an indivisible granularity of ipset member. + type: object + required: + - Type + - Member + properties: + Type: + $ref: "#/definitions/IpsetType" + Member: + $ref: "#/definitions/IpsetMember" + IpsetInfo: + description: > + IpsetInfo contains all parameters and information for ipset operations. + type: object + required: + - Type + - Name + properties: + Type: + type: string + $ref: "#/definitions/IpsetType" + Name: + type: string + minLength: 1 + maxLength: 32 # IPSET_MAXNAMELEN = 32 + Opcode: + description: opertaion type code + type: integer + format: uint16 + enum: + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + x-enum-varnames: + - Add + - Del + - Test + - Create + - Destroy + - Flush + - List + CreationOptions: + $ref: '#/definitions/IpsetCreationOption' + Entries: + type: array + items: + $ref: "#/definitions/IpsetMember" + IpsetInfoArray: + description: IpsetInfoArray contains an array of ipset. + type: object + properties: + Count: + type: integer + format: int32 + Infos: + type: array + items: + $ref: "#/definitions/IpsetInfo" paths: /device: get: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/stats" summary: "display all net device list" @@ -654,10 +807,9 @@ paths: schema: type: string /device/{name}/addr: - #description: dpip addr add 192.168.88.16/32 dev dpdk0.102 get: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/stats" - "$ref": "#/parameters/verbose" @@ -674,7 +826,7 @@ paths: type: string put: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/snapshot" - "$ref": "#/parameters/sapool" @@ -696,7 +848,7 @@ paths: type: string delete: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/sapool" - "$ref": "#/parameters/device-name" @@ -712,10 +864,9 @@ paths: schema: type: string /device/{name}/route: - #description: dpip route add 192.168.88.16/32 dev dpdk0.102 scope kni_host get: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/stats" - "$ref": "#/parameters/device-name" @@ -731,7 +882,7 @@ paths: type: string put: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" - "$ref": "#/parameters/route-config" @@ -751,7 +902,7 @@ paths: type: string delete: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" - "$ref": "#/parameters/route-config" @@ -768,7 +919,7 @@ paths: /device/{name}/netlink: get: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" - "$ref": "#/parameters/stats" @@ -784,7 +935,7 @@ paths: type: string put: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" summary: "ip link set ${name} up" @@ -799,7 +950,7 @@ paths: type: string delete: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" summary: "ip link set ${name} down" @@ -815,7 +966,7 @@ paths: /device/{name}/netlink/addr: get: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" - "$ref": "#/parameters/stats" @@ -831,12 +982,13 @@ paths: type: string put: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/snapshot" - "$ref": "#/parameters/device-name" - "$ref": "#/parameters/device-addr" - summary: "ip addr add 10.0.0.1/32 dev eth0: Set ip cird to linux net device" + summary: | + ip addr add 10.0.0.1/32 dev eth0: Set ip cird to linux net device responses: '200': description: Success @@ -848,11 +1000,12 @@ paths: type: string delete: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" - "$ref": "#/parameters/device-addr" - summary: "ip addr del 10.0.0.1/32 dev eth0: Delete ip cird fron linux net device" + summary: | + ip addr del 10.0.0.1/32 dev eth0: Delete ip cird fron linux net device responses: '200': description: Success @@ -862,12 +1015,10 @@ paths: description: Not Found schema: type: string - #/device/{name}/cpu /device/{name}/nic: - #description: dpip link show get: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" - "$ref": "#/parameters/verbose" @@ -877,20 +1028,22 @@ paths: '200': description: Success schema: - "$ref": "#/definitions/NicDeviceSpecList" + "$ref": "#/definitions/NicDeviceSpecList" '500': description: Failure schema: type: string put: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" - "$ref": "#/parameters/forward2kni" - "$ref": "#/parameters/link" - "$ref": "#/parameters/promisc" - summary: "dpip link set ${nic-name} [forward2kni,link,promisc,tc-ingress,tc-egress] [on/up,off/down]" + summary: > + dpip link set ${nic-name} + [forward2kni,link,promisc,tc-ingress,tc-egress] [on/up,off/down] responses: '200': description: Success @@ -901,10 +1054,9 @@ paths: schema: type: string /device/{name}/vlan: - #description: dpip vlan add dpdk0.102 link dpdk0 id 102 get: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" - "$ref": "#/parameters/stats" @@ -920,7 +1072,7 @@ paths: type: string put: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" - "$ref": "#/parameters/vlan-config" @@ -936,7 +1088,7 @@ paths: type: string delete: tags: - - "device" + - "device" parameters: - "$ref": "#/parameters/device-name" summary: "delete special net device" @@ -952,7 +1104,7 @@ paths: /vs: get: tags: - - "virtualserver" + - "virtualserver" parameters: - "$ref": "#/parameters/stats" - "$ref": "#/parameters/snapshot" @@ -971,7 +1123,7 @@ paths: /vs/{VipPort}: get: tags: - - "virtualserver" + - "virtualserver" parameters: - "$ref": "#/parameters/snapshot" - "$ref": "#/parameters/healthcheck" @@ -984,7 +1136,7 @@ paths: schema: "$ref": "#/definitions/VirtualServerList" '404': - description: Service not found + description: Service not found schema: type: string delete: @@ -1028,7 +1180,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1042,7 +1194,7 @@ paths: /vs/{VipPort}/laddr: get: tags: - - "virtualserver" + - "virtualserver" parameters: - "$ref": "#/parameters/snapshot" - "$ref": "#/parameters/service-id" @@ -1058,7 +1210,7 @@ paths: type: string put: tags: - - "virtualserver" + - "virtualserver" parameters: - "$ref": "#/parameters/snapshot" - "$ref": "#/parameters/service-id" @@ -1076,7 +1228,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1089,7 +1241,7 @@ paths: "$ref": "#/definitions/Error" delete: tags: - - "virtualserver" + - "virtualserver" parameters: - "$ref": "#/parameters/service-id" - "$ref": "#/parameters/laddr-config" @@ -1102,7 +1254,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1125,19 +1277,18 @@ paths: responses: '200': description: Success - #schema: - # "$ref": "#/definitions/RealServerExpandList" '270': - description: "the rss-config parameter is outdated, update nothing and return the latest rs info" + description: > + the rss-config parameter is outdated, + update nothing and return the latest rs info x-go-name: Unexpected schema: - # "$ref": "#/definitions/RealServerExpandList" "$ref": "#/definitions/VirtualServerSpecExpand" '460': description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1151,7 +1302,7 @@ paths: /vs/{VipPort}/rs: get: tags: - - "virtualserver" + - "virtualserver" parameters: - "$ref": "#/parameters/snapshot" - "$ref": "#/parameters/service-id" @@ -1162,7 +1313,7 @@ paths: schema: type: string '404': - description: Service not found + description: Service not found schema: type: string delete: @@ -1183,7 +1334,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1214,7 +1365,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1246,7 +1397,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1260,7 +1411,7 @@ paths: /vs/{VipPort}/deny: get: tags: - - "virtualserver" + - "virtualserver" parameters: - "$ref": "#/parameters/service-id" responses: @@ -1269,7 +1420,7 @@ paths: schema: type: string '404': - description: Service not found + description: Service not found schema: type: string delete: @@ -1290,7 +1441,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1321,7 +1472,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1352,7 +1503,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1366,7 +1517,7 @@ paths: /vs/{VipPort}/allow: get: tags: - - "virtualserver" + - "virtualserver" parameters: - "$ref": "#/parameters/service-id" responses: @@ -1375,7 +1526,7 @@ paths: schema: type: string '404': - description: Service not found + description: Service not found schema: type: string delete: @@ -1396,7 +1547,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1427,7 +1578,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1458,7 +1609,7 @@ paths: description: Invalid frontend in service configuration x-go-name: InvalidFrontend schema: - "$ref": "#/definitions/Error" + "$ref": "#/definitions/Error" '461': description: Invalid backend in service configuration x-go-name: InvalidBackend @@ -1469,3 +1620,209 @@ paths: x-go-name: Failure schema: "$ref": "#/definitions/Error" + /ipset: + get: + summary: "Get all the ipsets and members." + tags: + - "ipset" + operationId: GetAll + responses: + '200': + description: Success + schema: + $ref: "#/definitions/IpsetInfoArray" + '500': + description: Service not available + x-go-name: Failure + schema: + type: string + /ipset/{name}: + get: + summary: "Get a specific ipset and its members." + tags: + - "ipset" + operationId: Get + parameters: + - "$ref": "#/parameters/ipset-name" + responses: + '200': + description: Success + schema: + $ref: "#/definitions/IpsetInfo" + '404': + description: Ipset not found + schema: + type: string + '500': + description: Service not available + x-go-name: Failure + schema: + type: string + put: + summary: "Create an ipset named {name}." + tags: + - "ipset" + operationId: Create + parameters: + - $ref: "#/parameters/ipset-name" + - $ref: "#/parameters/ipset-param" + responses: + '200': + description: Replaced + schema: + type: string + '201': + description: Created + schema: + type: string + '400': + description: Invalid ipset parameter + schema: + type: string + '404': + description: Ipset not found + schema: + type: string + '500': + description: Service not available + x-go-name: Failure + schema: + type: string + delete: + summary: "Delete the ipset named {name}." + tags: + - "ipset" + operationId: Destroy + parameters: + - $ref: "#/parameters/ipset-name" + responses: + '200': + description: Deleted + schema: + type: string + '404': + description: Ipset not found + schema: + type: string + '500': + description: Service not available + x-go-name: Failure + schema: + type: string + /ipset/{name}/cell: + post: + summary: "Check if an object in the ipset." + tags: + - "ipset" + operationId: IsIn + parameters: + - $ref: "#/parameters/ipset-name" + - $ref: "#/parameters/ipset-cell" + responses: + '200': + description: Succeed + schema: + type: object + required: + - Result + properties: + Result: + type: boolean + Message: + type: string + '400': + description: Invalid ipset parameter + schema: + type: string + '404': + description: Ipset not found + schema: + type: string + '500': + description: Service not available + x-go-name: Failure + schema: + type: string + /ipset/{name}/member: + post: + summary: "Add members to the ipset." + tags: + - "ipset" + operationId: AddMember + parameters: + - $ref: "#/parameters/ipset-name" + - $ref: "#/parameters/ipset-param" + responses: + '200': + description: Existed + schema: + type: string + '201': + description: Created + schema: + type: string + '400': + description: Invalid ipset parameter + schema: + type: string + '404': + description: Ipset not found + schema: + type: string + '500': + description: Service not available + x-go-name: Failure + schema: + type: string + delete: + summary: "Delete members from the ipset." + tags: + - "ipset" + operationId: DelMember + parameters: + - $ref: "#/parameters/ipset-name" + - $ref: "#/parameters/ipset-param" + responses: + '200': + description: Succeed + schema: + type: string + '400': + description: Invalid ipset parameter + schema: + type: string + '404': + description: Ipset not found + schema: + type: string + '500': + description: Service not available + x-go-name: Failure + schema: + type: string + put: + summary: "Reset the whole ipset members." + tags: + - "ipset" + operationId: ReplaceMember + parameters: + - $ref: "#/parameters/ipset-name" + - $ref: "#/parameters/ipset-param" + responses: + '200': + description: Succeed + schema: + type: string + '400': + description: Invalid ipset parameter + schema: + type: string + '404': + description: Ipset not found + schema: + type: string + '500': + description: Service not available + x-go-name: Failure + schema: + type: string diff --git a/tools/dpvs-agent/models/cert_auth_spec.go b/tools/dpvs-agent/models/cert_auth_spec.go index 61648012e..a7896bd28 100644 --- a/tools/dpvs-agent/models/cert_auth_spec.go +++ b/tools/dpvs-agent/models/cert_auth_spec.go @@ -19,6 +19,9 @@ type CertAuthSpec struct { // addr Addr string `json:"addr,omitempty"` + + // ipset + Ipset string `json:"ipset,omitempty"` } // Validate validates this cert auth spec diff --git a/tools/dpvs-agent/models/ipset_cell.go b/tools/dpvs-agent/models/ipset_cell.go new file mode 100644 index 000000000..280262d27 --- /dev/null +++ b/tools/dpvs-agent/models/ipset_cell.go @@ -0,0 +1,159 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// IpsetCell IpsetCell represents an indivisible granularity of ipset member. +// +// swagger:model IpsetCell +type IpsetCell struct { + + // member + // Required: true + Member *IpsetMember `json:"Member"` + + // type + // Required: true + Type *IpsetType `json:"Type"` +} + +// Validate validates this ipset cell +func (m *IpsetCell) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMember(formats); err != nil { + res = append(res, err) + } + + if err := m.validateType(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *IpsetCell) validateMember(formats strfmt.Registry) error { + + if err := validate.Required("Member", "body", m.Member); err != nil { + return err + } + + if m.Member != nil { + if err := m.Member.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Member") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Member") + } + return err + } + } + + return nil +} + +func (m *IpsetCell) validateType(formats strfmt.Registry) error { + + if err := validate.Required("Type", "body", m.Type); err != nil { + return err + } + + if err := validate.Required("Type", "body", m.Type); err != nil { + return err + } + + if m.Type != nil { + if err := m.Type.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Type") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Type") + } + return err + } + } + + return nil +} + +// ContextValidate validate this ipset cell based on the context it is used +func (m *IpsetCell) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMember(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateType(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *IpsetCell) contextValidateMember(ctx context.Context, formats strfmt.Registry) error { + + if m.Member != nil { + if err := m.Member.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Member") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Member") + } + return err + } + } + + return nil +} + +func (m *IpsetCell) contextValidateType(ctx context.Context, formats strfmt.Registry) error { + + if m.Type != nil { + if err := m.Type.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Type") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Type") + } + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *IpsetCell) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *IpsetCell) UnmarshalBinary(b []byte) error { + var res IpsetCell + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/tools/dpvs-agent/models/ipset_creation_option.go b/tools/dpvs-agent/models/ipset_creation_option.go new file mode 100644 index 000000000..ff176fb85 --- /dev/null +++ b/tools/dpvs-agent/models/ipset_creation_option.go @@ -0,0 +1,118 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// IpsetCreationOption IpsetCreationOption contains all available options required in creating an ipset. +// +// swagger:model IpsetCreationOption +type IpsetCreationOption struct { + + // comment + Comment *bool `json:"Comment,omitempty"` + + // family + // Enum: [ipv4 ipv6] + Family string `json:"Family,omitempty"` + + // hash max elem + HashMaxElem uint32 `json:"HashMaxElem,omitempty"` + + // hash size + HashSize uint32 `json:"HashSize,omitempty"` + + // vaild format: ipv4-ipv4, ipv4/pfx, ipv6/pfx, port-port + // + Range string `json:"Range,omitempty"` +} + +// Validate validates this ipset creation option +func (m *IpsetCreationOption) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateFamily(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var ipsetCreationOptionTypeFamilyPropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ipv4","ipv6"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + ipsetCreationOptionTypeFamilyPropEnum = append(ipsetCreationOptionTypeFamilyPropEnum, v) + } +} + +const ( + + // IpsetCreationOptionFamilyIPV4 captures enum value "ipv4" + IpsetCreationOptionFamilyIPV4 string = "ipv4" + + // IpsetCreationOptionFamilyIPV6 captures enum value "ipv6" + IpsetCreationOptionFamilyIPV6 string = "ipv6" +) + +// prop value enum +func (m *IpsetCreationOption) validateFamilyEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, ipsetCreationOptionTypeFamilyPropEnum, true); err != nil { + return err + } + return nil +} + +func (m *IpsetCreationOption) validateFamily(formats strfmt.Registry) error { + if swag.IsZero(m.Family) { // not required + return nil + } + + // value enum + if err := m.validateFamilyEnum("Family", "body", m.Family); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this ipset creation option based on context it is used +func (m *IpsetCreationOption) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *IpsetCreationOption) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *IpsetCreationOption) UnmarshalBinary(b []byte) error { + var res IpsetCreationOption + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/tools/dpvs-agent/models/ipset_info.go b/tools/dpvs-agent/models/ipset_info.go new file mode 100644 index 000000000..39e6b1e2b --- /dev/null +++ b/tools/dpvs-agent/models/ipset_info.go @@ -0,0 +1,284 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// IpsetInfo IpsetInfo contains all parameters and information for ipset operations. +// +// swagger:model IpsetInfo +type IpsetInfo struct { + + // creation options + CreationOptions *IpsetCreationOption `json:"CreationOptions,omitempty"` + + // entries + Entries []*IpsetMember `json:"Entries"` + + // name + // Required: true + // Max Length: 32 + // Min Length: 1 + Name *string `json:"Name"` + + // opertaion type code + // Enum: [1 2 3 4 5 6 7] + Opcode uint16 `json:"Opcode,omitempty"` + + // type + // Required: true + Type *IpsetType `json:"Type"` +} + +// Validate validates this ipset info +func (m *IpsetInfo) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateCreationOptions(formats); err != nil { + res = append(res, err) + } + + if err := m.validateEntries(formats); err != nil { + res = append(res, err) + } + + if err := m.validateName(formats); err != nil { + res = append(res, err) + } + + if err := m.validateOpcode(formats); err != nil { + res = append(res, err) + } + + if err := m.validateType(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *IpsetInfo) validateCreationOptions(formats strfmt.Registry) error { + if swag.IsZero(m.CreationOptions) { // not required + return nil + } + + if m.CreationOptions != nil { + if err := m.CreationOptions.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("CreationOptions") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("CreationOptions") + } + return err + } + } + + return nil +} + +func (m *IpsetInfo) validateEntries(formats strfmt.Registry) error { + if swag.IsZero(m.Entries) { // not required + return nil + } + + for i := 0; i < len(m.Entries); i++ { + if swag.IsZero(m.Entries[i]) { // not required + continue + } + + if m.Entries[i] != nil { + if err := m.Entries[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Entries" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Entries" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +func (m *IpsetInfo) validateName(formats strfmt.Registry) error { + + if err := validate.Required("Name", "body", m.Name); err != nil { + return err + } + + if err := validate.MinLength("Name", "body", *m.Name, 1); err != nil { + return err + } + + if err := validate.MaxLength("Name", "body", *m.Name, 32); err != nil { + return err + } + + return nil +} + +var ipsetInfoTypeOpcodePropEnum []interface{} + +func init() { + var res []uint16 + if err := json.Unmarshal([]byte(`[1,2,3,4,5,6,7]`), &res); err != nil { + panic(err) + } + for _, v := range res { + ipsetInfoTypeOpcodePropEnum = append(ipsetInfoTypeOpcodePropEnum, v) + } +} + +// prop value enum +func (m *IpsetInfo) validateOpcodeEnum(path, location string, value uint16) error { + if err := validate.EnumCase(path, location, value, ipsetInfoTypeOpcodePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *IpsetInfo) validateOpcode(formats strfmt.Registry) error { + if swag.IsZero(m.Opcode) { // not required + return nil + } + + // value enum + if err := m.validateOpcodeEnum("Opcode", "body", m.Opcode); err != nil { + return err + } + + return nil +} + +func (m *IpsetInfo) validateType(formats strfmt.Registry) error { + + if err := validate.Required("Type", "body", m.Type); err != nil { + return err + } + + if err := validate.Required("Type", "body", m.Type); err != nil { + return err + } + + if m.Type != nil { + if err := m.Type.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Type") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Type") + } + return err + } + } + + return nil +} + +// ContextValidate validate this ipset info based on the context it is used +func (m *IpsetInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateCreationOptions(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateEntries(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateType(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *IpsetInfo) contextValidateCreationOptions(ctx context.Context, formats strfmt.Registry) error { + + if m.CreationOptions != nil { + if err := m.CreationOptions.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("CreationOptions") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("CreationOptions") + } + return err + } + } + + return nil +} + +func (m *IpsetInfo) contextValidateEntries(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Entries); i++ { + + if m.Entries[i] != nil { + if err := m.Entries[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Entries" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Entries" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +func (m *IpsetInfo) contextValidateType(ctx context.Context, formats strfmt.Registry) error { + + if m.Type != nil { + if err := m.Type.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Type") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Type") + } + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *IpsetInfo) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *IpsetInfo) UnmarshalBinary(b []byte) error { + var res IpsetInfo + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/tools/dpvs-agent/models/ipset_info_array.go b/tools/dpvs-agent/models/ipset_info_array.go new file mode 100644 index 000000000..432e65ff3 --- /dev/null +++ b/tools/dpvs-agent/models/ipset_info_array.go @@ -0,0 +1,119 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// IpsetInfoArray IpsetInfoArray contains an array of ipset. +// +// swagger:model IpsetInfoArray +type IpsetInfoArray struct { + + // count + Count int32 `json:"Count,omitempty"` + + // infos + Infos []*IpsetInfo `json:"Infos"` +} + +// Validate validates this ipset info array +func (m *IpsetInfoArray) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateInfos(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *IpsetInfoArray) validateInfos(formats strfmt.Registry) error { + if swag.IsZero(m.Infos) { // not required + return nil + } + + for i := 0; i < len(m.Infos); i++ { + if swag.IsZero(m.Infos[i]) { // not required + continue + } + + if m.Infos[i] != nil { + if err := m.Infos[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Infos" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Infos" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// ContextValidate validate this ipset info array based on the context it is used +func (m *IpsetInfoArray) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateInfos(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *IpsetInfoArray) contextValidateInfos(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Infos); i++ { + + if m.Infos[i] != nil { + if err := m.Infos[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Infos" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Infos" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *IpsetInfoArray) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *IpsetInfoArray) UnmarshalBinary(b []byte) error { + var res IpsetInfoArray + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/tools/dpvs-agent/models/ipset_member.go b/tools/dpvs-agent/models/ipset_member.go new file mode 100644 index 000000000..c1ac8bab2 --- /dev/null +++ b/tools/dpvs-agent/models/ipset_member.go @@ -0,0 +1,151 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// IpsetMember IpsetMember represents a specific entry in ipset. +// +// swagger:model IpsetMember +type IpsetMember struct { + + // comment + // Max Length: 32 + // Min Length: 1 + Comment string `json:"Comment,omitempty"` + + // type specific entry data, for example + // * 192.168.1.0/29 (bitmap:ip) + // * 192.168.88.0/24,tcp:8080-8082 (hash:net) + // * 2001::1,8080-8082,2002::aaaa:bbbb:ccc0:0/108 (hash:ip,port,net) + // + // Required: true + Entry *string `json:"Entry"` + + // options + Options *IpsetOption `json:"Options,omitempty"` +} + +// Validate validates this ipset member +func (m *IpsetMember) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateComment(formats); err != nil { + res = append(res, err) + } + + if err := m.validateEntry(formats); err != nil { + res = append(res, err) + } + + if err := m.validateOptions(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *IpsetMember) validateComment(formats strfmt.Registry) error { + if swag.IsZero(m.Comment) { // not required + return nil + } + + if err := validate.MinLength("Comment", "body", m.Comment, 1); err != nil { + return err + } + + if err := validate.MaxLength("Comment", "body", m.Comment, 32); err != nil { + return err + } + + return nil +} + +func (m *IpsetMember) validateEntry(formats strfmt.Registry) error { + + if err := validate.Required("Entry", "body", m.Entry); err != nil { + return err + } + + return nil +} + +func (m *IpsetMember) validateOptions(formats strfmt.Registry) error { + if swag.IsZero(m.Options) { // not required + return nil + } + + if m.Options != nil { + if err := m.Options.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Options") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Options") + } + return err + } + } + + return nil +} + +// ContextValidate validate this ipset member based on the context it is used +func (m *IpsetMember) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateOptions(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *IpsetMember) contextValidateOptions(ctx context.Context, formats strfmt.Registry) error { + + if m.Options != nil { + if err := m.Options.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("Options") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("Options") + } + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *IpsetMember) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *IpsetMember) UnmarshalBinary(b []byte) error { + var res IpsetMember + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/tools/dpvs-agent/models/ipset_option.go b/tools/dpvs-agent/models/ipset_option.go new file mode 100644 index 000000000..a250729c0 --- /dev/null +++ b/tools/dpvs-agent/models/ipset_option.go @@ -0,0 +1,55 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// IpsetOption IpsetOption defines common options for ipset operations. +// +// swagger:model IpsetOption +type IpsetOption struct { + + // When add members to ipset with Force set, the already existing members are replaced sliently instead of emitting an EDPVS_EXIST error; When delete non-existent memebers from ipset, the DPSVS_NOTEXIST error is ignored. + // + Force *bool `json:"Force,omitempty"` + + // Nomatch excludes a small element range from an ipset, which is mainly used by network-cidr based ipset. + // + NoMatch *bool `json:"NoMatch,omitempty"` +} + +// Validate validates this ipset option +func (m *IpsetOption) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this ipset option based on context it is used +func (m *IpsetOption) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *IpsetOption) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *IpsetOption) UnmarshalBinary(b []byte) error { + var res IpsetOption + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/tools/dpvs-agent/models/ipset_type.go b/tools/dpvs-agent/models/ipset_type.go new file mode 100644 index 000000000..ecf655aa8 --- /dev/null +++ b/tools/dpvs-agent/models/ipset_type.go @@ -0,0 +1,108 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" +) + +// IpsetType ipset type +// +// swagger:model IpsetType +type IpsetType string + +func NewIpsetType(value IpsetType) *IpsetType { + return &value +} + +// Pointer returns a pointer to a freshly-allocated IpsetType. +func (m IpsetType) Pointer() *IpsetType { + return &m +} + +const ( + + // IpsetTypeBitmapIP captures enum value "bitmap:ip" + IpsetTypeBitmapIP IpsetType = "bitmap:ip" + + // IpsetTypeBitmapIPMac captures enum value "bitmap:ip,mac" + IpsetTypeBitmapIPMac IpsetType = "bitmap:ip,mac" + + // IpsetTypeBitmapPort captures enum value "bitmap:port" + IpsetTypeBitmapPort IpsetType = "bitmap:port" + + // IpsetTypeHashIP captures enum value "hash:ip" + IpsetTypeHashIP IpsetType = "hash:ip" + + // IpsetTypeHashNet captures enum value "hash:net" + IpsetTypeHashNet IpsetType = "hash:net" + + // IpsetTypeHashIPPort captures enum value "hash:ip,port" + IpsetTypeHashIPPort IpsetType = "hash:ip,port" + + // IpsetTypeHashNetPort captures enum value "hash:net,port" + IpsetTypeHashNetPort IpsetType = "hash:net,port" + + // IpsetTypeHashNetPortIface captures enum value "hash:net,port,iface" + IpsetTypeHashNetPortIface IpsetType = "hash:net,port,iface" + + // IpsetTypeHashIPPortIP captures enum value "hash:ip,port,ip" + IpsetTypeHashIPPortIP IpsetType = "hash:ip,port,ip" + + // IpsetTypeHashIPPortNet captures enum value "hash:ip,port,net" + IpsetTypeHashIPPortNet IpsetType = "hash:ip,port,net" + + // IpsetTypeHashNetPortNet captures enum value "hash:net,port,net" + IpsetTypeHashNetPortNet IpsetType = "hash:net,port,net" + + // IpsetTypeHashNetPortNetPort captures enum value "hash:net,port,net,port" + IpsetTypeHashNetPortNetPort IpsetType = "hash:net,port,net,port" +) + +// for schema +var ipsetTypeEnum []interface{} + +func init() { + var res []IpsetType + if err := json.Unmarshal([]byte(`["bitmap:ip","bitmap:ip,mac","bitmap:port","hash:ip","hash:net","hash:ip,port","hash:net,port","hash:net,port,iface","hash:ip,port,ip","hash:ip,port,net","hash:net,port,net","hash:net,port,net,port"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + ipsetTypeEnum = append(ipsetTypeEnum, v) + } +} + +func (m IpsetType) validateIpsetTypeEnum(path, location string, value IpsetType) error { + if err := validate.EnumCase(path, location, value, ipsetTypeEnum, true); err != nil { + return err + } + return nil +} + +// Validate validates this ipset type +func (m IpsetType) Validate(formats strfmt.Registry) error { + var res []error + + // value enum + if err := m.validateIpsetTypeEnum("", "body", m); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// ContextValidate validates this ipset type based on context it is used +func (m IpsetType) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} diff --git a/tools/dpvs-agent/pkg/ipc/types/certificate.go b/tools/dpvs-agent/pkg/ipc/types/certificate.go index 5f8ea82a5..7916bd897 100644 --- a/tools/dpvs-agent/pkg/ipc/types/certificate.go +++ b/tools/dpvs-agent/pkg/ipc/types/certificate.go @@ -31,14 +31,19 @@ import ( "github.com/dpvs-agent/pkg/ipc/pool" ) +/* +derived from: + - include/conf/blklst.h + - include/conf/whtlst.h +*/ type CertificateAuthoritySpec struct { - src [0x10]byte - dst [0x10]byte - af uint32 - fwmark uint32 - port uint16 - proto uint8 - padding uint8 + vaddr [0x10]byte + vport uint16 + proto uint8 + af uint8 + + caddr [0x10]byte + ipset [IPSET_MAXNAMELEN]byte } type CertificateAuthorityFront struct { @@ -54,12 +59,12 @@ func NewCertificateAuthorityFront() *CertificateAuthorityFront { } func (o *CertificateAuthoritySpec) Copy(src *CertificateAuthoritySpec) bool { - o.af = src.af - o.fwmark = src.fwmark - o.port = src.port + copy(o.vaddr[:], src.vaddr[:]) + o.vport = src.vport o.proto = src.proto - copy(o.src[:], src.src[:]) - copy(o.dst[:], src.dst[:]) + o.af = src.af + copy(o.caddr[:], src.caddr[:]) + copy(o.ipset[:], src.ipset[:]) return true } @@ -80,19 +85,19 @@ func (o *CertificateAuthoritySpec) ParseVipPortProto(vipport string) error { o.proto = unix.IPPROTO_TCP } - // port := items[1] - port, err := strconv.Atoi(items[1]) + // vport := items[1] + vport, err := strconv.Atoi(items[1]) if err != nil { return err } - o.SetPort(uint16(port)) + o.SetVport(uint16(vport)) - vip := items[0] - if net.ParseIP(vip) == nil { - return errors.New(fmt.Sprintf("invalid ip addr: %s\n", vip)) + vaddr := items[0] + if net.ParseIP(vaddr) == nil { + return errors.New(fmt.Sprintf("invalid ip addr: %s\n", vaddr)) } - o.SetDst(vip) + o.SetVaddr(vaddr) return nil } @@ -150,42 +155,53 @@ func (o *CertificateAuthorityFront) GetCount() uint32 { return o.count } -func (o *CertificateAuthoritySpec) SetAf(af uint32) { +func (o *CertificateAuthoritySpec) SetAf(af uint8) { o.af = af } -func (o *CertificateAuthoritySpec) SetSrc(addr string) { +func (o *CertificateAuthoritySpec) SetCaddr(addr string) { + if len(addr) == 0 { + var zeros [0x10]byte + copy(o.caddr[:], zeros[:]) + return + } if strings.Contains(addr, ":") { o.SetAf(unix.AF_INET6) - copy(o.src[:], net.ParseIP(addr)) + copy(o.caddr[:], net.ParseIP(addr)) return } o.SetAf(unix.AF_INET) buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, net.ParseIP(addr)) - copy(o.src[:], buf.Bytes()[12:]) + copy(o.caddr[:], buf.Bytes()[12:]) } -func (o *CertificateAuthoritySpec) SetDst(addr string) { +func (o *CertificateAuthoritySpec) SetVaddr(addr string) { if strings.Contains(addr, ":") { o.SetAf(unix.AF_INET6) - copy(o.dst[:], net.ParseIP(addr)) + copy(o.vaddr[:], net.ParseIP(addr)) return } o.SetAf(unix.AF_INET) buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, net.ParseIP(addr)) - copy(o.dst[:], buf.Bytes()[12:]) + copy(o.vaddr[:], buf.Bytes()[12:]) } -func (o *CertificateAuthoritySpec) SetFwmark(fwmark uint32) { - o.fwmark = fwmark +func (o *CertificateAuthoritySpec) SetIpset(ipset string) { + if len(ipset) == 0 { + var zeros [IPSET_MAXNAMELEN]byte + copy(o.ipset[:], zeros[:]) + return + } + buf := []byte(ipset) + copy(o.ipset[:], buf[6:]) } -func (o *CertificateAuthoritySpec) SetPort(port uint16) { +func (o *CertificateAuthoritySpec) SetVport(port uint16) { buf := new(bytes.Buffer) binary.Write(buf, binary.LittleEndian, uint16(port)) - o.port = binary.BigEndian.Uint16(buf.Bytes()) + o.vport = binary.BigEndian.Uint16(buf.Bytes()) } func (o *CertificateAuthoritySpec) SetProto(proto string) { diff --git a/tools/dpvs-agent/pkg/ipc/types/const.go b/tools/dpvs-agent/pkg/ipc/types/const.go index 590b48d14..ade0c16c8 100644 --- a/tools/dpvs-agent/pkg/ipc/types/const.go +++ b/tools/dpvs-agent/pkg/ipc/types/const.go @@ -241,6 +241,7 @@ const ( SOCKOPT_SET_IFADDR_SET SOCKOPT_SET_IFADDR_FLUSH SOCKOPT_GET_IFADDR_SHOW + SOCKOPT_GET_IFMADDR_SHOW SOCKOPT_NETIF_SET_LCORE SOCKOPT_NETIF_SET_PORT @@ -255,8 +256,12 @@ const ( SOCKOPT_NETIF_GET_PORT_XSTATS SOCKOPT_NETIF_GET_PORT_EXT_INFO SOCKOPT_NETIF_GET_BOND_STATUS + SOCKOPT_NETIF_GET_MADDR SOCKOPT_NETIF_GET_MAX + SOCKOPT_SET_LLDP_TODO + SOCKOPT_GET_LLDP_SHOW + SOCKOPT_SET_NEIGH_ADD SOCKOPT_SET_NEIGH_DEL SOCKOPT_GET_NEIGH_SHOW diff --git a/tools/dpvs-agent/pkg/ipc/types/ipset.go b/tools/dpvs-agent/pkg/ipc/types/ipset.go new file mode 100644 index 000000000..eec5d508f --- /dev/null +++ b/tools/dpvs-agent/pkg/ipc/types/ipset.go @@ -0,0 +1,948 @@ +// Copyright 2023 IQiYi Inc. All Rights Reserved. +// +// 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 types + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "net" + "syscall" + "unsafe" + + "github.com/dpvs-agent/pkg/ipc/pool" + "github.com/hashicorp/go-hclog" + "golang.org/x/sys/unix" +) + +// The consts mirrors const macros defined in conf/ipset.h +const ( + IPSET_MAXNAMELEN = 32 + IPSET_MAXCOMLEN = 32 + + IPSET_F_FORCE = 0x0001 +) + +// The consts mirrors `enum ipset_op` defined in conf/ipset.h +const ( + _ uint16 = iota + IPSET_OP_ADD + IPSET_OP_DEL + IPSET_OP_TEST + IPSET_OP_CREATE + IPSET_OP_DESTROY + IPSET_OP_FLUSH + IPSET_OP_LIST + IPSET_OP_MAX +) + +// InetAddrRange mirrors `struct inet_addr_range` defined in conf/inet.h +type InetAddrRange struct { + minAddr [16]byte + maxAddr [16]byte + minPort uint16 + maxPort uint16 +} + +func (o *InetAddrRange) SetMinAddr(ip net.IP) { + if ip == nil { + return + } + if ip4 := ip.To4(); ip4 != nil { + copy(o.minAddr[:4], ip4[:4]) + } else { + copy(o.minAddr[:], ip[:]) + } +} + +func (o *InetAddrRange) SetMaxAddr(ip net.IP) { + if ip == nil { + return + } + if ip4 := ip.To4(); ip4 != nil { + copy(o.maxAddr[:4], ip4[:4]) + } else { + copy(o.maxAddr[:], ip[:]) + } +} + +func (o *InetAddrRange) SetMinPort(port uint16) { + o.minPort = port +} + +func (o *InetAddrRange) SetMaxPort(port uint16) { + o.maxPort = port +} + +func (o *InetAddrRange) Decode(af uint8) (net.IP, net.IP, uint16, uint16) { + if af == syscall.AF_INET6 { + minAddr := make(net.IP, net.IPv6len) + maxAddr := make(net.IP, net.IPv6len) + copy(minAddr[:], o.minAddr[:16]) + copy(maxAddr[:], o.maxAddr[:16]) + return minAddr, maxAddr, o.minPort, o.maxPort + } else { + minAddr := net.IPv4(o.minAddr[0], o.minAddr[1], o.minAddr[2], o.minAddr[3]) + maxAddr := net.IPv4(o.maxAddr[0], o.maxAddr[1], o.maxAddr[2], o.maxAddr[3]) + return minAddr, maxAddr, o.minPort, o.maxPort + } + return nil, nil, 0, 0 // never hit +} + +func (o *InetAddrRange) Sizeof() uint64 { + return uint64(unsafe.Sizeof(*o)) +} + +func (o *InetAddrRange) Copy(from *InetAddrRange) bool { + if from == nil { + return false + } + copy(o.minAddr[:], from.minAddr[:]) + copy(o.maxAddr[:], from.maxAddr[:]) + o.minPort = from.minPort + o.maxPort = from.maxPort + return true +} + +// IPSetParam mirrors `struct ipset_param` defined in conf/ipset.h +type IPSetParam struct { + kind [IPSET_MAXNAMELEN]byte + name [IPSET_MAXNAMELEN]byte + comment [IPSET_MAXCOMLEN]byte + opcode uint16 + flag uint16 + + // flat reflection of `struct ipset_option`: + // ops create: af(8), comment(8), hashSize(4), maxElem(4) + // ops add: af(8), nomatch(8) + hashSize uint32 + maxElem uint32 + commentOrNomatch uint8 + af uint8 + + proto uint8 + cidr uint8 + addrRange InetAddrRange + iface [unix.IFNAMSIZ]byte + macAddr [6]byte + + // for ipset types with 2 nets + _ uint8 + cidr2 uint8 + addrRange2 InetAddrRange +} + +func (o *IPSetParam) getKind() string { + return string(bytes.TrimRight(o.kind[:], "\x00")) +} + +func (o *IPSetParam) SetKind(kind string) { + if len(kind) > 0 { + copy(o.kind[:], kind) + } +} + +func (o *IPSetParam) SetName(name string) { + if len(name) > 0 { + copy(o.name[:], name) + } +} + +func (o *IPSetParam) SetComment(comment string) { + if len(comment) > 0 { + copy(o.comment[:], comment) + } +} + +func (o *IPSetParam) SetOpcode(opcode uint16) { + o.opcode = opcode +} + +func (o *IPSetParam) SetFlag(flag uint16) { + o.flag = flag +} + +func (o *IPSetParam) AddFlag(flag uint16) { + o.flag |= flag +} + +func (o *IPSetParam) DelFlag(flag uint16) { + o.flag &= ^flag +} + +func (o *IPSetParam) SetAf(af uint8) { + o.af = af +} + +func (o *IPSetParam) SetCommentFlag(enable bool) { + num := 0 + if enable { + num = 1 + } + o.commentOrNomatch = uint8(num) +} + +func (o *IPSetParam) SetNomatch(enable bool) { + num := 0 + if enable { + num = 1 + } + o.commentOrNomatch = uint8(num) +} + +func (o *IPSetParam) SetHashSize(hashSize uint32) { + o.hashSize = hashSize +} + +func (o *IPSetParam) SetMaxElem(maxElem uint32) { + o.maxElem = maxElem +} + +func (o *IPSetParam) SetProto(proto uint8) { + o.proto = proto +} + +func (o *IPSetParam) SetCidr(cidr uint8) { + o.cidr = cidr +} + +func (o *IPSetParam) GetAddrRange() *InetAddrRange { + return &o.addrRange +} + +func (o *IPSetParam) SetIface(iface string) { + if len(iface) > 0 { + copy(o.iface[:], iface) + } +} + +func (o *IPSetParam) SetMacAddr(macAddr string) error { + n, err := fmt.Sscanf(macAddr, "%02x:%02x:%02x:%02x:%02x:%02x", + &o.macAddr[0], &o.macAddr[1], &o.macAddr[2], + &o.macAddr[3], &o.macAddr[4], &o.macAddr[5]) + if err != nil { + return err + } + if n != 6 { + return fmt.Errorf("string macAddr parsed to %d parts, expected 6", n) + } + return nil +} + +func (o *IPSetParam) SetCidr2(cidr uint8) { + o.cidr2 = cidr +} + +func (o *IPSetParam) GetAddrRange2() *InetAddrRange { + return &o.addrRange2 +} + +func (o *IPSetParam) Sizeof() uint64 { + return uint64(unsafe.Sizeof(*o)) +} + +func (o *IPSetParam) Copy(from *IPSetParam) bool { + if from == nil { + return false + } + copy(o.kind[:], from.kind[:]) + copy(o.name[:], from.name[:]) + copy(o.comment[:], from.comment[:]) + o.opcode = from.opcode + o.flag = from.flag + + o.af = from.af + o.commentOrNomatch = from.commentOrNomatch + o.hashSize = from.hashSize + o.maxElem = from.maxElem + + o.proto = from.proto + o.cidr = from.cidr + o.addrRange.Copy(&from.addrRange) + o.iface = from.iface + o.macAddr = from.macAddr + + o.cidr2 = from.cidr2 + o.addrRange2.Copy(&from.addrRange2) + + return true +} + +func (o *IPSetParam) Dump(buf []byte) bool { + var to *IPSetParam + if len(buf) < int(o.Sizeof()) { + return false + } + to = *(**IPSetParam)(unsafe.Pointer(&buf)) + return o.Copy(to) +} + +func (o *IPSetParam) Package() []byte { + buf := new(bytes.Buffer) + binary.Write(buf, binary.LittleEndian, o) + return buf.Bytes() +} + +func (o *IPSetParam) write(conn *pool.Conn) error { + buf := o.Package() + n, err := conn.WriteN(buf, int(o.Sizeof())) + if err != nil { + return fmt.Errorf("IPSetParam write error: %v, %d of %d written\n", + err, n, o.Sizeof()) + } + return nil +} + +type IPSetParamArray []IPSetParam + +// IPSetMember mirrors `struct ipset_meber` defined in conf/ipset.h +type IPSetMember struct { + comment [IPSET_MAXCOMLEN]byte + + addr [16]byte + cidr uint8 + proto uint8 + port uint16 + iface [unix.IFNAMSIZ]byte + macAddr [6]byte + nomatch uint8 + + // for ipset types with 2 nets + cidr2 uint8 + port2 uint16 + _ [2]uint8 + addr2 [16]byte +} + +func (o *IPSetMember) GetComment() string { + return string(bytes.TrimRight(o.comment[:], "\x00")) +} + +func (o *IPSetMember) GetAddr(af uint8) net.IP { + if af == syscall.AF_INET6 { + res := make(net.IP, net.IPv6len) + copy(res, o.addr[:]) + return res + } + return net.IPv4(o.addr[0], o.addr[1], o.addr[2], o.addr[3]) +} + +func (o *IPSetMember) GetCidr() uint8 { + return o.cidr +} + +func (o *IPSetMember) GetProto() uint8 { + return o.proto +} + +func (o *IPSetMember) GetPort() uint16 { + return o.port +} + +func (o *IPSetMember) GetIface() string { + return string(bytes.TrimRight(o.iface[:], "\x00")) +} + +func (o *IPSetMember) GetMacAddr() string { + return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", + o.macAddr[0], o.macAddr[1], o.macAddr[2], + o.macAddr[3], o.macAddr[4], o.macAddr[5]) +} + +func (o *IPSetMember) GetNoMatch() bool { + if o.nomatch > 0 { + return true + } + return false +} + +func (o *IPSetMember) GetCidr2() uint8 { + return o.cidr2 +} + +func (o *IPSetMember) GetPort2() uint16 { + return o.port2 +} + +func (o *IPSetMember) GetAddr2(af uint8) net.IP { + if af == syscall.AF_INET6 { + res := make(net.IP, net.IPv6len) + copy(res, o.addr2[:]) + return res + } + return net.IPv4(o.addr2[0], o.addr2[1], o.addr2[2], o.addr2[3]) +} + +func (o *IPSetMember) Sizeof() uint64 { + return uint64(unsafe.Sizeof(*o)) +} + +func (o *IPSetMember) Copy(from *IPSetMember) bool { + if from == nil { + return false + } + + copy(o.comment[:], from.comment[:]) + + copy(o.addr[:], from.addr[:]) + o.cidr = from.cidr + o.proto = from.proto + o.port = from.port + copy(o.iface[:], from.iface[:]) + copy(o.macAddr[:], from.macAddr[:]) + o.nomatch = from.nomatch + + o.cidr2 = from.cidr2 + o.port2 = from.port2 + copy(o.addr2[:], from.addr2[:]) + + return true +} + +// IPSetInfo mirrors `struct ipset_info` defined in conf/ipset.h +type IPSetInfo struct { + name [IPSET_MAXNAMELEN]byte + kind [IPSET_MAXNAMELEN]byte + comment uint8 + + af uint8 + _ [2]uint8 + + // kind bitmap: cidr(8), addrRange(20) + // kind hash: hashSize(4), hashMaxElem(4) + cidr uint8 + _ [3]uint8 + hashSizeOrAddrRange uint32 + hashMaxElem uint32 + __reserved [28]uint8 + + size uint32 + entries uint32 + references uint32 + + membersPtr uintptr + members []IPSetMember +} + +func (o *IPSetInfo) GetName() string { + return string(bytes.TrimRight(o.name[:], "\x00")) +} + +func (o *IPSetInfo) GetKind() string { + return string(bytes.TrimRight(o.kind[:], "\x00")) +} + +func (o *IPSetInfo) GetComment() bool { + if o.comment > 0 { + return true + } + return false +} + +func (o *IPSetInfo) GetAf() uint8 { + return o.af +} + +func (o *IPSetInfo) GetCidr() uint8 { + return o.cidr +} + +func (o *IPSetInfo) GetAddrRange() (net.IP, net.IP, uint16, uint16) { + iaRange := (*InetAddrRange)(unsafe.Pointer(uintptr(unsafe.Pointer(&o.hashSizeOrAddrRange)))) + return iaRange.Decode(o.af) +} + +func (o *IPSetInfo) GetHashSize() uint32 { + return o.hashSizeOrAddrRange +} + +func (o *IPSetInfo) GetSize() uint32 { + return o.size +} + +func (o *IPSetInfo) GetEntries() uint32 { + return o.entries +} + +func (o *IPSetInfo) GetReferences() uint32 { + return o.references +} + +func (o *IPSetInfo) GetHashMaxElem() uint32 { + return o.hashMaxElem +} + +func (o *IPSetInfo) GetMembers() []IPSetMember { + return o.members +} + +func (o *IPSetInfo) Sizeof() uint64 { + return uint64(unsafe.Offsetof(o.members)) +} + +func (o *IPSetInfo) Copy(from *IPSetInfo) bool { + if from == nil { + return false + } + + copy(o.name[:], from.name[:]) + copy(o.kind[:], from.kind[:]) + o.comment = from.comment + + o.af = from.af + + o.cidr = from.cidr + o.hashSizeOrAddrRange = from.hashSizeOrAddrRange + o.hashMaxElem = from.hashMaxElem + copy(o.__reserved[:], from.__reserved[:]) + + o.size = from.size + o.entries = from.entries + o.references = from.references + + //// Note: + //// Do NOT copy members! They are not in C struct. + // o.members = make([]IPSetMember, len(from.members)) + // for i, _ := range from.members { + // o.members[i].Copy(&from.members[i]) + // } + + return true +} + +// IPSetInfoArray interprets `struct ipset_info_array` defined in conf/ipset.h +type IPSetInfoArray struct { + infos []IPSetInfo +} + +func (o *IPSetInfoArray) GetIPSetInfos() []IPSetInfo { + return o.infos +} + +func (o *IPSetInfoArray) read(conn *pool.Conn, logger hclog.Logger) error { + var info *IPSetInfo + var member *IPSetMember + var i, j, nipset uint32 + var offset uint64 + + dataLen := uint64(unsafe.Sizeof(nipset)) + buf, err := conn.ReadN(int(dataLen)) + if err != nil { + return fmt.Errorf("Read IPSetInfo number failed: %v", err) + } + nipset = binary.LittleEndian.Uint32(buf[:dataLen]) + if nipset == 0 { + return nil + } + + // read IPSetInfo data + dataLen = (uint64(nipset)) * info.Sizeof() + buf, err = conn.ReadN(int(dataLen)) + if err != nil { + return fmt.Errorf("Read IPSetInfo data failed: %v", err) + } + + dataLen = 0 + offset = 0 + o.infos = make([]IPSetInfo, nipset) + for i = 0; i < nipset; i++ { + info = (*IPSetInfo)(unsafe.Pointer(uintptr(unsafe.Pointer(&buf[offset])))) + o.infos[i].Copy(info) + offset += info.Sizeof() + dataLen += uint64(info.entries) * member.Sizeof() + } + if dataLen == 0 { + return nil + } + + // read IPSetMember data + buf, err = conn.ReadN(int(dataLen)) + if err != nil { + return fmt.Errorf("Read IPSetMember data failed: %v", err) + } + offset = 0 + for i = 0; i < nipset; i++ { + o.infos[i].members = make([]IPSetMember, o.infos[i].entries) + for j = 0; j < o.infos[i].entries; j++ { + member = (*IPSetMember)(unsafe.Pointer(uintptr(unsafe.Pointer(&buf[offset])))) + o.infos[i].members[j].Copy(member) + offset += member.Sizeof() + } + } + + return nil +} + +type CheckResult int32 + +func (o *CheckResult) Sizeof() uint64 { + return uint64(unsafe.Sizeof(*o)) +} + +func (o *CheckResult) Dump(buf []byte) bool { + if len(buf) != int(o.Sizeof()) { + return false + } + reader := bytes.NewReader(buf) + if err := binary.Read(reader, binary.LittleEndian, o); err != nil { + return false + } + return true +} + +func (o *CheckResult) read(conn *pool.Conn, logger hclog.Logger) error { + buf, err := conn.ReadN(int(o.Sizeof())) + if err != nil { + return fmt.Errorf("Read ipset check result failed: %v", err) + } + if o.Dump(buf) != true { + return fmt.Errorf("Dump ipset check result failed") + } + return nil +} + +func getLogger(name string, parent hclog.Logger) hclog.Logger { + if parent != nil { + return parent.Named(name) + } + return hclog.Default().Named(name) +} + +func (o *IPSetParam) Get(cp *pool.ConnPool, parentLogger hclog.Logger) (*IPSetInfoArray, error, DpvsErrType) { + logger := getLogger("ipset:get", parentLogger) + + if o.opcode != IPSET_OP_LIST { + logger.Error("Invalid ipset opcode for Get", "opcode", o.opcode) + return nil, fmt.Errorf("invalid ipset opcode %d for get", o.opcode), 0 + } + + ctx := context.Background() + conn, err := cp.Get(ctx) + if err != nil { + logger.Error("Get conn from pool failed", "Error", err.Error()) + return nil, err, 0 + } + defer cp.Remove(ctx, conn, nil) + + msg := NewSockMsg(SOCKOPT_VERSION, SOCKOPT_GET_IPSET_LIST, SOCKOPT_GET, o.Sizeof()) + if err = msg.Write(conn); err != nil { + logger.Error("SOCKOPT_GET_IPSET_LIST write proto header failed", "Error", err.Error()) + return nil, err, 0 + } + + if err = o.write(conn); err != nil { + logger.Error("SOCKOPT_GET_IPSET_LIST write ipset param failed", "Error", err.Error()) + return nil, err, 0 + } + + reply := NewReplySockMsg() + if err = reply.Read(conn); err != nil { + logger.Error("SOCKOPT_GET_IPSET_LIST read reply header failed", "Error", err.Error()) + return nil, err, 0 + } + if reply.GetErrCode() != EDPVS_OK { + errStr := reply.GetErrStr() + logger.Error("SOCKOPT_GET_IPSET_LIST replied error", "DPVS.Error", errStr) + return nil, fmt.Errorf("DPVS Response Error: %s", errStr), reply.GetErrCode() + } + + output := &IPSetInfoArray{} + if reply.GetLen() > 0 { + err = output.read(conn, logger) + if err != nil { + logger.Error("SOCKOPT_GET_IPSET_LIST read reply data failed", "Error", err.Error()) + return nil, err, 0 + } + } + return output, nil, 0 +} + +func (o *IPSetParam) CreateDestroy(cp *pool.ConnPool, parentLogger hclog.Logger) (error, DpvsErrType) { + if o.opcode != IPSET_OP_CREATE && o.opcode != IPSET_OP_DESTROY { + return fmt.Errorf("invalid ipset opcode %d for Create/Destroy", o.opcode), 0 + } + logName := "ipset:create" + if o.opcode == IPSET_OP_DESTROY { + logName = "ipset:destroy" + } + logger := getLogger(logName, parentLogger) + + ctx := context.Background() + conn, err := cp.Get(ctx) + if err != nil { + logger.Error("Get conn from pool failed", "Error", err.Error()) + return err, 0 + } + defer cp.Remove(ctx, conn, nil) + + msg := NewSockMsg(SOCKOPT_VERSION, SOCKOPT_SET_IPSET, SOCKOPT_SET, o.Sizeof()) + if err = msg.Write(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET write proto header failed", "Error", err.Error()) + return err, 0 + } + + if err = o.write(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET write ipset param failed", "Error", err.Error()) + return err, 0 + } + + reply := NewReplySockMsg() + if err = reply.Read(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET read reply header failed", "Error", err.Error()) + return err, 0 + } + dpvsErrCode := reply.GetErrCode() + if dpvsErrCode != EDPVS_OK { + /* + if !(dpvsErrCode == EDPVS_EXIST && o.opcode == IPSET_OP_CREATE || + dpvsErrCode == EDPVS_NOTEXIST && o.opcode == IPSET_OP_DESTROY) { + errStr := reply.GetErrStr() + logger.Error("SOCKOPT_SET_IPSET replied error", "DPVS.Error", errStr) + return fmt.Errorf("DPVS Response Error: %s", errStr), reply.GetErrCode() + } + */ + errStr := reply.GetErrStr() + logger.Error("SOCKOPT_SET_IPSET replied error", "DPVS.Error", errStr) + return fmt.Errorf("DPVS Response Error: %s", errStr), reply.GetErrCode() + } + return nil, 0 +} + +func (o *IPSetParam) IsIn(cp *pool.ConnPool, parentLogger hclog.Logger) (bool, error, DpvsErrType) { + logger := getLogger("ipset:isin", parentLogger) + + result := false + if o.opcode != IPSET_OP_TEST { + logger.Error("Invalid ipset opcode for TEST", "opcode", o.opcode) + return result, fmt.Errorf("invalid ipset opcode %d for TEST", o.opcode), 0 + } + + ctx := context.Background() + conn, err := cp.Get(ctx) + if err != nil { + logger.Error("Get conn from pool failed", "Error", err.Error()) + return result, err, 0 + } + defer cp.Remove(ctx, conn, nil) + + msg := NewSockMsg(SOCKOPT_VERSION, SOCKOPT_GET_IPSET_TEST, SOCKOPT_GET, o.Sizeof()) + if err = msg.Write(conn); err != nil { + logger.Error("SOCKOPT_GET_IPSET_TEST write proto header failed", "Error", err.Error()) + return result, err, 0 + } + + if err = o.write(conn); err != nil { + logger.Error("SOCKOPT_GET_IPSET_TEST write ipset param failed", "Error", err.Error()) + return result, err, 0 + } + + reply := NewReplySockMsg() + if err = reply.Read(conn); err != nil { + logger.Error("SOCKOPT_GET_IPSET_TEST read reply header failed", "Error", err.Error()) + return result, err, 0 + } + if reply.GetErrCode() != EDPVS_OK { + errStr := reply.GetErrStr() + logger.Error("SOCKOPT_GET_IPSET_TEST replied error", "DPVS.Error", errStr) + return result, fmt.Errorf("DPVS Response Error: %s", errStr), reply.GetErrCode() + } + + var output CheckResult + err = output.read(conn, logger) + if err != nil { + logger.Error("SOCKOPT_GET_IPSET_LIST read reply data failed", "Error", err.Error()) + return result, err, 0 + } + if output > 0 { + result = true + } + return result, nil, 0 +} + +func (o *IPSetParamArray) AddDelMember(cp *pool.ConnPool, parentLogger hclog.Logger) (error, DpvsErrType) { + if len(*o) == 0 { + return nil, 0 + } + opcode := (*o)[0].opcode + if opcode != IPSET_OP_ADD && opcode != IPSET_OP_DEL { + return fmt.Errorf("invalid ipset opcode %d for Add/Del", opcode), 0 + } + name := (*o)[0].name + for _, param := range *o { + if opcode != param.opcode { + return fmt.Errorf("ipset opcode in param array did not match for Add/Del"), 0 + } + if !bytes.Equal(name[:], param.name[:]) { + return fmt.Errorf("ipset name in param array did not match for Add/Del"), 0 + } + } + + logName := "ipset:add" + if opcode == IPSET_OP_DEL { + logName = "ipset:del" + } + logger := getLogger(logName, parentLogger) + + for _, param := range *o { + ctx := context.Background() + conn, err := cp.Get(ctx) + if err != nil { + logger.Error("Get conn from pool failed", "Error", err.Error()) + return err, 0 + } + + msg := NewSockMsg(SOCKOPT_VERSION, SOCKOPT_SET_IPSET, SOCKOPT_SET, param.Sizeof()) + if err = msg.Write(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET write proto header failed", "Error", err.Error()) + cp.Remove(ctx, conn, nil) + return err, 0 + } + + if err = param.write(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET write ipset param failed", "Error", err.Error()) + cp.Remove(ctx, conn, nil) + return err, 0 + } + + reply := NewReplySockMsg() + if err = reply.Read(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET read reply header failed", "Error", err.Error()) + cp.Remove(ctx, conn, nil) + return err, 0 + } + cp.Remove(ctx, conn, nil) + + dpvsErrCode := reply.GetErrCode() + if dpvsErrCode != EDPVS_OK { + /* + if dpvsErrCode == EDPVS_EXIST && opcode == IPSET_OP_ADD || + dpvsErrCode == EDPVS_NOTEXIST && opcode == IPSET_OP_DEL { + continue + } + */ + errStr := reply.GetErrStr() + logger.Error("SOCKOPT_SET_IPSET replied error", "DPVS.Error", errStr) + return fmt.Errorf("DPVS Response Error: %s", errStr), reply.GetErrCode() + } + } + return nil, 0 +} + +func (o *IPSetParamArray) ReplaceMember(cp *pool.ConnPool, parentLogger hclog.Logger) (error, DpvsErrType) { + if len(*o) == 0 { + return nil, 0 + } + opcode := (*o)[0].opcode + if opcode != IPSET_OP_ADD && opcode != IPSET_OP_FLUSH { + return fmt.Errorf("invalid ipset opcode %d for Replace", opcode), 0 + } + name := (*o)[0].name + for i, param := range *o { + if i == 0 { + continue + } + if opcode != param.opcode { + return fmt.Errorf("ipset opcode in param array did not match for Replace"), 0 + } + if !bytes.Equal(name[:], param.name[:]) { + return fmt.Errorf("ipset name in param array did not match for Repalce"), 0 + } + } + + logger := getLogger("replace", parentLogger) + + // Flush the whole ipset + param := &IPSetParam{} + param.Copy(&(*o)[0]) + param.opcode = IPSET_OP_FLUSH + + ctx := context.Background() + conn, err := cp.Get(ctx) + if err != nil { + logger.Error("Get conn from pool failed", "Error", err.Error()) + return err, 0 + } + + msg := NewSockMsg(SOCKOPT_VERSION, SOCKOPT_SET_IPSET, SOCKOPT_SET, param.Sizeof()) + if err = msg.Write(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET write proto header failed", "Error", err.Error()) + cp.Remove(ctx, conn, nil) + return err, 0 + } + + if err = param.write(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET write ipset param failed", "Error", err.Error()) + cp.Remove(ctx, conn, nil) + return err, 0 + } + + reply := NewReplySockMsg() + if err = reply.Read(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET read reply header failed", "Error", err.Error()) + cp.Remove(ctx, conn, nil) + return err, 0 + } + cp.Remove(ctx, conn, nil) + + if reply.GetErrCode() != EDPVS_OK { + errStr := reply.GetErrStr() + logger.Error("SOCKOPT_SET_IPSET replied error", "DPVS.Error", errStr) + return fmt.Errorf("DPVS Response Error: %s", errStr), reply.GetErrCode() + } + + if opcode != IPSET_OP_ADD { + return nil, 0 + } + + // Add members into ipset + for _, param := range *o { + ctx := context.Background() + conn, err := cp.Get(ctx) + if err != nil { + logger.Error("Get conn from pool failed", "Error", err.Error()) + return err, 0 + } + + msg := NewSockMsg(SOCKOPT_VERSION, SOCKOPT_SET_IPSET, SOCKOPT_SET, param.Sizeof()) + if err = msg.Write(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET write proto header failed", "Error", err.Error()) + cp.Remove(ctx, conn, nil) + return err, 0 + } + + if err = param.write(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET write ipset param failed", "Error", err.Error()) + cp.Remove(ctx, conn, nil) + return err, 0 + } + + reply := NewReplySockMsg() + if err = reply.Read(conn); err != nil { + logger.Error("SOCKOPT_SET_IPSET read reply header failed", "Error", err.Error()) + cp.Remove(ctx, conn, nil) + return err, 0 + } + cp.Remove(ctx, conn, nil) + + dpvsErrCode := reply.GetErrCode() + if dpvsErrCode != EDPVS_OK { + errStr := reply.GetErrStr() + logger.Error("SOCKOPT_SET_IPSET replied error", "DPVS.Error", errStr) + return fmt.Errorf("DPVS Response Error: %s", errStr), reply.GetErrCode() + } + } + return nil, 0 +} diff --git a/tools/dpvs-agent/pkg/ipc/types/ipset_models.go b/tools/dpvs-agent/pkg/ipc/types/ipset_models.go new file mode 100644 index 000000000..203cad130 --- /dev/null +++ b/tools/dpvs-agent/pkg/ipc/types/ipset_models.go @@ -0,0 +1,1305 @@ +// Copyright 2023 IQiYi Inc. All Rights Reserved. +// +// 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 types + +import ( + "encoding/binary" + "fmt" + "net" + "strconv" + "strings" + "syscall" + "unicode" + + "github.com/dpvs-agent/models" +) + +var ( + _ IPSetType = (*IPSetBitmapIP)(nil) + _ IPSetType = (*IPSetBitmapIPMac)(nil) + _ IPSetType = (*IPSetBitmapPort)(nil) + _ IPSetType = (*IPSetHashIP)(nil) + _ IPSetType = (*IPSetHashNet)(nil) + _ IPSetType = (*IPSetHashIPPort)(nil) + _ IPSetType = (*IPSetHashNetPort)(nil) + _ IPSetType = (*IPSetHashNetPortIface)(nil) + _ IPSetType = (*IPSetHashIPPortIP)(nil) + _ IPSetType = (*IPSetHashIPPortNet)(nil) + _ IPSetType = (*IPSetHashNetPortNet)(nil) + _ IPSetType = (*IPSetHashNetPortNetPort)(nil) +) + +type IPSetType interface { + // Update IPSetParam with parsed fields from models.IpsetMember.Entry + ParseEntry(string, *IPSetParam) error + // Create a models.IpsetMember with Entry field filled + ModelEntry(uint8, *IPSetMember) (*models.IpsetMember, error) + // Check if IPSetParam is valid + CheckParam(*IPSetParam) error +} + +type IPSetBitmapIP struct{} +type IPSetBitmapIPMac struct{} +type IPSetBitmapPort struct{} +type IPSetHashIP struct{} +type IPSetHashNet struct{} +type IPSetHashIPPort struct{} +type IPSetHashNetPort struct{} +type IPSetHashNetPortIface struct{} +type IPSetHashIPPortIP struct{} +type IPSetHashIPPortNet struct{} +type IPSetHashNetPortNet struct{} +type IPSetHashNetPortNetPort struct{} + +func (o *IPSetBitmapIP) ParseEntry(entry string, param *IPSetParam) error { + startIP, endIP, af, pfx, err := parseAddrRange(entry) + if err != nil { + return fmt.Errorf("Parse models.IpsetMember Entry failed: %v", err) + } + + param.SetAf(af) + if startIP != nil { + param.GetAddrRange().SetMinAddr(startIP) + } + if endIP != nil { + param.GetAddrRange().SetMaxAddr(endIP) + } else { + param.GetAddrRange().SetMaxAddr(startIP) + } + param.SetCidr(pfx) + + return nil +} + +func (o *IPSetBitmapIP) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + entry := "" + + if member.GetCidr() > 0 { + entry = fmt.Sprintf("%s/%d", member.GetAddr(af), member.GetCidr()) + } else { + entry = fmt.Sprintf("%s", member.GetAddr(af)) + } + model.Entry = &entry + + return model, nil +} + +func (o *IPSetBitmapIP) CheckParam(param *IPSetParam) error { + if param.af == syscall.AF_INET6 { + return fmt.Errorf("bitmap:ip doesn't support ipv6") + } + if param.opcode != IPSET_OP_CREATE { + return nil + } + if param.cidr > 0 { + if param.cidr < 16 { + return fmt.Errorf("bitmap:ip net seg too big, cidr should be no smaller than 16") + } + return nil + } + if param.af == syscall.AF_INET { + startIP, endIP, _, _ := param.addrRange.Decode(param.af) + if ip4ToUint32(startIP) >= ip4ToUint32(endIP) { + return fmt.Errorf("bitmap:ip requires a network range or cidr") + } + } + return nil +} + +func (o *IPSetBitmapIPMac) ParseEntry(entry string, param *IPSetParam) error { + segs := strings.Split(entry, ",") + + startIP, endIP, af, pfx, err := parseAddrRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid addr range %s", segs[0]) + } + param.SetAf(af) + if startIP != nil { + param.GetAddrRange().SetMinAddr(startIP) + } + if endIP != nil { + param.GetAddrRange().SetMaxAddr(endIP) + } else { + param.GetAddrRange().SetMaxAddr(startIP) + } + param.SetCidr(pfx) + + if len(segs) > 1 { + if err := param.SetMacAddr(segs[1]); err != nil { + return fmt.Errorf("invalid mac address: %s", err.Error()) + } + } + + return nil +} + +func (o *IPSetBitmapIPMac) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + entry := fmt.Sprintf("%s,%s", member.GetAddr(af), member.GetMacAddr()) + model.Entry = &entry + + return model, nil +} + +func (o *IPSetBitmapIPMac) CheckParam(param *IPSetParam) error { + if param.af == syscall.AF_INET6 { + return fmt.Errorf("bitmap:ip,mac doesn't support ipv6") + } + if param.opcode != IPSET_OP_CREATE { + if param.cidr > 0 { + return fmt.Errorf("bitmap:ip,mac doesn't support addr cidr") + } + if param.af == syscall.AF_INET { + startIP, endIP, _, _ := param.addrRange.Decode(param.af) + if endIP != nil && !endIP.Equal(startIP) { + return fmt.Errorf("bitmap:ip,mac doesn't support addr range") + } + } + } else { + if param.cidr > 0 { + if param.cidr < 16 { + return fmt.Errorf("bitmap:ip,mac net seg too big, cidr should be no smaller than 16") + } + return nil + } + if param.af == syscall.AF_INET { + startIP, endIP, _, _ := param.addrRange.Decode(param.af) + if ip4ToUint32(startIP) >= ip4ToUint32(endIP) { + return fmt.Errorf("bitmap:ip,mac create requires a network range or cidr") + } + } + } + return nil +} + +func (o *IPSetBitmapPort) ParseEntry(entry string, param *IPSetParam) error { + startPort, endPort, proto, err := parsePortRange(entry) + if err != nil { + return err + } + param.GetAddrRange().SetMinPort(startPort) + if endPort > 0 { + param.GetAddrRange().SetMaxPort(endPort) + } else { + param.GetAddrRange().SetMaxPort(startPort) + } + param.SetProto(proto) + return nil +} + +func (o *IPSetBitmapPort) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + + entry := fmt.Sprintf("%s:%d", protoString(member.GetProto()), member.GetPort()) + model.Entry = &entry + + return model, nil +} + +func (o *IPSetBitmapPort) CheckParam(param *IPSetParam) error { + if param.opcode == IPSET_OP_CREATE { + if param.proto != 0 { + return fmt.Errorf("bitmap:port doesn't support proto in create") + } + } else { + if param.addrRange.minPort > 0 && + param.proto != syscall.IPPROTO_TCP && param.proto != syscall.IPPROTO_UDP { + return fmt.Errorf("invalid bitmap:port protocol %s", protoString(param.proto)) + } + } + return nil +} + +func (o *IPSetHashIP) ParseEntry(entry string, param *IPSetParam) error { + startIP, endIP, af, pfx, err := parseAddrRange(entry) + if err != nil { + return fmt.Errorf("invalid addr range %s", entry) + } + param.SetAf(af) + if startIP != nil { + param.GetAddrRange().SetMinAddr(startIP) + } + if endIP != nil { + param.GetAddrRange().SetMaxAddr(endIP) + } else { + param.GetAddrRange().SetMaxAddr(startIP) + } + param.SetCidr(pfx) + return nil +} + +func (o *IPSetHashIP) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + + entry := member.GetAddr(af).String() + model.Entry = &entry + + return model, nil +} + +func (o *IPSetHashIP) CheckParam(param *IPSetParam) error { + if param.opcode != IPSET_OP_ADD && param.opcode != IPSET_OP_DEL { + return nil + } + if param.af == syscall.AF_INET6 { + if param.cidr > 0 { + return fmt.Errorf("hash:ip doesn't support IPv6 cidr") + } + } else if param.af == syscall.AF_INET { + if param.cidr > 0 && param.cidr < 16 { + return fmt.Errorf("ipv4 address cidr range too big, 65536 at most") + } + } + startIP, endIP, _, _ := param.addrRange.Decode(param.af) + if param.af == syscall.AF_INET { + startIPNum, endIPNum := ip4ToUint32(startIP), ip4ToUint32(endIP) + if endIPNum > 0 && endIPNum-startIPNum >= 65535 { + return fmt.Errorf("ipv4 address range too big, 65536 at most") + } + } + return nil +} + +func (o *IPSetHashNet) ParseEntry(entry string, param *IPSetParam) error { + // the same as IPSetHashIP + var iphash IPSetHashIP + return iphash.ParseEntry(entry, param) +} + +func (o *IPSetHashNet) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + + entry := fmt.Sprintf("%s/%d", member.GetAddr(af).String(), member.GetCidr()) + model.Entry = &entry + + return model, nil +} + +func (o *IPSetHashNet) CheckParam(param *IPSetParam) error { + // nothing to do + return nil +} + +func (o *IPSetHashIPPort) ParseEntry(entry string, param *IPSetParam) error { + segs := strings.Split(entry, ",") + + startIP, endIP, af, pfx, err := parseAddrRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid addr range %s", segs[0]) + } + param.SetAf(af) + if startIP != nil { + param.GetAddrRange().SetMinAddr(startIP) + } + if endIP != nil { + param.GetAddrRange().SetMaxAddr(endIP) + } else { + param.GetAddrRange().SetMaxAddr(startIP) + } + param.SetCidr(pfx) + + if len(segs) > 1 { + startPort, endPort, proto, err := parsePortRange(segs[1]) + if err != nil { + return err + } + param.GetAddrRange().SetMinPort(startPort) + if endPort > 0 { + param.GetAddrRange().SetMaxPort(endPort) + } else { + param.GetAddrRange().SetMaxPort(startPort) + } + param.SetProto(proto) + } + + return nil +} + +func (o *IPSetHashIPPort) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + + entry := fmt.Sprintf("%s,%s:%d", + member.GetAddr(af).String(), + protoString(member.GetProto()), + member.GetPort()) + model.Entry = &entry + + return model, nil +} + +func (o *IPSetHashIPPort) CheckParam(param *IPSetParam) error { + if param.opcode != IPSET_OP_ADD && param.opcode != IPSET_OP_DEL { + return nil + } + if param.af == syscall.AF_INET6 { + if param.cidr > 0 { + return fmt.Errorf("hash:ip,port doesn't support IPv6 cidr") + } + } else if param.af == syscall.AF_INET { + if param.cidr > 0 && param.cidr < 24 { + return fmt.Errorf("ipv4 address cidr range too big, 256 at most") + } + } + + startIP, endIP, startPort, endPort := param.addrRange.Decode(param.af) + if param.af == syscall.AF_INET { + startIPNum, endIPNum := ip4ToUint32(startIP), ip4ToUint32(endIP) + if endIPNum > 0 && endIPNum-startIPNum >= 256 { + return fmt.Errorf("ipv4 address range too big, 256 at most") + } + } + if endPort > 0 && endPort-startPort >= 256 { + return fmt.Errorf("port range too big, 256 at most") + } + return nil +} + +func (o *IPSetHashNetPort) ParseEntry(entry string, param *IPSetParam) error { + // the same as IPSetHashIPPort + var ipport IPSetHashIPPort + return ipport.ParseEntry(entry, param) +} + +func (o *IPSetHashNetPort) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + + entry := fmt.Sprintf("%s/%d,%s:%d", + member.GetAddr(af).String(), + member.GetPort(), + protoString(member.GetProto()), + member.GetPort()) + model.Entry = &entry + + return model, nil +} + +func (o *IPSetHashNetPort) CheckParam(param *IPSetParam) error { + // nothing to do + return nil +} + +func (o *IPSetHashNetPortIface) ParseEntry(entry string, param *IPSetParam) error { + segs := strings.Split(entry, ",") + if len(segs) < 3 { + return fmt.Errorf("invalid hash:net,port,iface entry: %s", entry) + } + + startIP, endIP, af, pfx, err := parseAddrRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid addr range %s, error %v", segs[0], err) + } + param.SetAf(af) + if startIP != nil { + param.GetAddrRange().SetMinAddr(startIP) + } + if endIP != nil { + param.GetAddrRange().SetMaxAddr(endIP) + } else { + param.GetAddrRange().SetMaxAddr(startIP) + } + param.SetCidr(pfx) + + segs = segs[1:] + startPort, endPort, proto, err := parsePortRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid port range %s, error %v", segs[0], err) + } + param.GetAddrRange().SetMinPort(startPort) + if endPort > 0 { + param.GetAddrRange().SetMaxPort(endPort) + } else { + param.GetAddrRange().SetMaxPort(startPort) + } + param.SetProto(proto) + + segs = segs[1:] + if len(segs[0]) == 0 { + return fmt.Errorf("empty interface name") + } + param.SetIface(segs[0]) + + return nil +} + +func (o *IPSetHashNetPortIface) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + + entry := fmt.Sprintf("%s/%d,%s:%d,%s", + member.GetAddr(af).String(), + member.GetPort(), + protoString(member.GetProto()), + member.GetPort(), + member.GetIface()) + model.Entry = &entry + + return model, nil +} + +func (o *IPSetHashNetPortIface) CheckParam(param *IPSetParam) error { + // nothing to do + return nil +} + +func (o *IPSetHashIPPortIP) ParseEntry(entry string, param *IPSetParam) error { + segs := strings.Split(entry, ",") + if len(segs) < 3 { + return fmt.Errorf("invalid hash:ip,port,ip entry: %s", entry) + } + + startIP, endIP, af, pfx, err := parseAddrRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid addr range %s, error %v", segs[0], err) + } + param.SetAf(af) + if startIP != nil { + param.GetAddrRange().SetMinAddr(startIP) + } + if endIP != nil { + param.GetAddrRange().SetMaxAddr(endIP) + } else { + param.GetAddrRange().SetMaxAddr(startIP) + } + param.SetCidr(pfx) + + segs = segs[1:] + startPort, endPort, proto, err := parsePortRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid port range %s, err %v", segs[0], err) + } + param.GetAddrRange().SetMinPort(startPort) + if endPort > 0 { + param.GetAddrRange().SetMaxPort(endPort) + } else { + param.GetAddrRange().SetMaxPort(startPort) + } + param.SetProto(proto) + + segs = segs[1:] + startIP2, endIP2, af2, pfx2, err := parseAddrRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid addr range2 %s, error %v", segs[0], err) + } + if af2 != af { + return fmt.Errorf("address family mismatch in hash:ip,port,ip member") + } + if startIP2 != nil { + param.GetAddrRange2().SetMinAddr(startIP2) + } + if endIP2 != nil { + param.GetAddrRange2().SetMaxAddr(endIP2) + } else { + param.GetAddrRange2().SetMaxAddr(startIP2) + } + param.SetCidr2(pfx2) + + return nil +} + +func (o *IPSetHashIPPortIP) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + + entry := fmt.Sprintf("%s,%s:%d,%s", + member.GetAddr(af).String(), + protoString(member.GetProto()), + member.GetPort(), + member.GetAddr2(af).String()) + model.Entry = &entry + + return model, nil +} + +func (o *IPSetHashIPPortIP) CheckParam(param *IPSetParam) error { + if param.opcode != IPSET_OP_ADD && param.opcode != IPSET_OP_DEL { + return nil + } + + if param.af == syscall.AF_INET6 { + if param.cidr > 0 || param.cidr2 > 0 { + return fmt.Errorf("hash:ip,port,ip doesn't support IPv6 cidr") + } + } else if param.af == syscall.AF_INET { + if param.cidr > 0 && param.cidr < 24 { + return fmt.Errorf("ipv4 address cidr range too big, 256 at most") + } + if param.cidr2 > 0 && param.cidr2 < 24 { + return fmt.Errorf("ipv4 address cidr2 range too big, 256 at most") + } + } + + startIP, endIP, startPort, endPort := param.addrRange.Decode(param.af) + if param.af == syscall.AF_INET { + startIPNum, endIPNum := ip4ToUint32(startIP), ip4ToUint32(endIP) + if endIPNum > 0 && endIPNum-startIPNum >= 256 { + return fmt.Errorf("ipv4 address range too big, 256 at most") + } + } + if endPort > 0 && endPort-startPort >= 256 { + return fmt.Errorf("port range too big, 256 at most") + } + + startIP2, endIP2, _, _ := param.addrRange.Decode(param.af) + if param.af == syscall.AF_INET { + startIPNum2, endIPNum2 := ip4ToUint32(startIP2), ip4ToUint32(endIP2) + if endIPNum2 > 0 && endIPNum2-startIPNum2 >= 256 { + return fmt.Errorf("ipv4 address range2 too big, 256 at most") + } + } + + return nil +} + +func (o *IPSetHashIPPortNet) ParseEntry(entry string, param *IPSetParam) error { + segs := strings.Split(entry, ",") + if len(segs) < 3 { + return fmt.Errorf("invalid hash:ip,port,net entry: %s", entry) + } + + // Notes: The "ip" and "net" parts in hash:ip,port,net corresponds to addr range1 + // and addr range2 respectively, so that match from a source address network + // to a single dest address can be implemented easily. + + // the "ip" part corresponds to address range2 + startIP2, endIP2, af2, pfx2, err := parseAddrRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid addr range %s, error %v", segs[0], err) + } + param.SetAf(af2) + if startIP2 != nil { + param.GetAddrRange2().SetMinAddr(startIP2) + } + if endIP2 != nil { + param.GetAddrRange2().SetMaxAddr(endIP2) + } else { + param.GetAddrRange2().SetMaxAddr(startIP2) + } + param.SetCidr2(pfx2) + + // the "port" part + segs = segs[1:] + startPort, endPort, proto, err := parsePortRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid port range %s, err %v", segs[0], err) + } + param.GetAddrRange().SetMinPort(startPort) + if endPort > 0 { + param.GetAddrRange().SetMaxPort(endPort) + } else { + param.GetAddrRange().SetMaxPort(startPort) + } + param.SetProto(proto) + + // the "net" part corresponds to address range1 + segs = segs[1:] + startIP, endIP, af, pfx, err := parseAddrRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid addr range %s, error %v", segs[0], err) + } + if af != af2 { + return fmt.Errorf("address family mismatch in hash:ip,port,net member") + } + if startIP != nil { + param.GetAddrRange().SetMinAddr(startIP) + } + if endIP != nil { + param.GetAddrRange().SetMaxAddr(endIP) + } else { + param.GetAddrRange().SetMaxAddr(startIP) + } + param.SetCidr(pfx) + + return nil +} + +func (o *IPSetHashIPPortNet) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + + entry := fmt.Sprintf("%s/%d,%s:%d,%s", + member.GetAddr(af).String(), + member.GetCidr(), + protoString(member.GetProto()), + member.GetPort(), + member.GetAddr2(af).String()) + model.Entry = &entry + + return model, nil +} + +func (o *IPSetHashIPPortNet) CheckParam(param *IPSetParam) error { + if param.opcode != IPSET_OP_ADD && param.opcode != IPSET_OP_DEL { + return nil + } + + if param.af == syscall.AF_INET6 { + if param.cidr2 > 0 { + return fmt.Errorf("hash:ip,port,net doesn't support IPv6 cidr") + } + } else if param.af == syscall.AF_INET { + if param.cidr2 > 0 && param.cidr2 < 24 { + return fmt.Errorf("ipv4 address cidr2 range too big, 256 at most") + } + } + + _, _, startPort, endPort := param.addrRange.Decode(param.af) + if endPort > 0 && endPort-startPort >= 256 { + return fmt.Errorf("port range too big, 256 at most") + } + + startIP2, endIP2, _, _ := param.addrRange.Decode(param.af) + if param.af == syscall.AF_INET { + startIPNum2, endIPNum2 := ip4ToUint32(startIP2), ip4ToUint32(endIP2) + if endIPNum2 > 0 && endIPNum2-startIPNum2 >= 256 { + return fmt.Errorf("ipv4 address range2 too big, 256 at most") + } + } + + return nil +} + +func (o *IPSetHashNetPortNet) ParseEntry(entry string, param *IPSetParam) error { + // Notes: almost the same as IPSetHashIPPortIP except the error message, + + segs := strings.Split(entry, ",") + if len(segs) < 3 { + return fmt.Errorf("invalid hash:net,port,net entry: %s", entry) + } + + startIP, endIP, af, pfx, err := parseAddrRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid addr range %s, error %v", segs[0], err) + } + param.SetAf(af) + if startIP != nil { + param.GetAddrRange().SetMinAddr(startIP) + } + if endIP != nil { + param.GetAddrRange().SetMaxAddr(endIP) + } else { + param.GetAddrRange().SetMaxAddr(startIP) + } + param.SetCidr(pfx) + + segs = segs[1:] + startPort, endPort, proto, err := parsePortRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid port range %s, err %v", segs[0], err) + } + param.GetAddrRange().SetMinPort(startPort) + if endPort > 0 { + param.GetAddrRange().SetMaxPort(endPort) + } else { + param.GetAddrRange().SetMaxPort(startPort) + } + param.SetProto(proto) + + segs = segs[1:] + startIP2, endIP2, af2, pfx2, err := parseAddrRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid addr range2 %s, error %v", segs[0], err) + } + if af2 != af { + return fmt.Errorf("address family mismatch in hash:net,port,net member") + } + if startIP2 != nil { + param.GetAddrRange2().SetMinAddr(startIP2) + } + if endIP2 != nil { + param.GetAddrRange2().SetMaxAddr(endIP2) + } else { + param.GetAddrRange2().SetMaxAddr(startIP2) + } + param.SetCidr2(pfx2) + + return nil +} + +func (o *IPSetHashNetPortNet) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + + entry := fmt.Sprintf("%s/%d,%s:%d,%s/%d", + member.GetAddr(af).String(), + member.GetCidr(), + protoString(member.GetProto()), + member.GetPort(), + member.GetAddr2(af).String(), + member.GetCidr2()) + model.Entry = &entry + + return model, nil +} + +func (o *IPSetHashNetPortNet) CheckParam(param *IPSetParam) error { + // nothing to do + return nil +} + +func (o *IPSetHashNetPortNetPort) ParseEntry(entry string, param *IPSetParam) error { + segs := strings.Split(entry, ",") + if len(segs) < 4 { + return fmt.Errorf("invalid hash:net,port,net,port entry: %s", entry) + } + + startIP, endIP, af, pfx, err := parseAddrRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid addr range %s, error %v", segs[0], err) + } + param.SetAf(af) + if startIP != nil { + param.GetAddrRange().SetMinAddr(startIP) + } + if endIP != nil { + param.GetAddrRange().SetMaxAddr(endIP) + } else { + param.GetAddrRange().SetMaxAddr(startIP) + } + param.SetCidr(pfx) + + segs = segs[1:] + startPort, endPort, proto, err := parsePortRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid port range %s, err %v", segs[0], err) + } + param.GetAddrRange().SetMinPort(startPort) + if endPort > 0 { + param.GetAddrRange().SetMaxPort(endPort) + } else { + param.GetAddrRange().SetMaxPort(startPort) + } + param.SetProto(proto) + + segs = segs[1:] + startIP2, endIP2, af2, pfx2, err := parseAddrRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid addr range2 %s, error %v", segs[0], err) + } + if af2 != af { + return fmt.Errorf("address family mismatch in hash:net,port,net,port member") + } + if startIP2 != nil { + param.GetAddrRange2().SetMinAddr(startIP2) + } + if endIP2 != nil { + param.GetAddrRange2().SetMaxAddr(endIP2) + } else { + param.GetAddrRange2().SetMaxAddr(startIP2) + } + param.SetCidr2(pfx2) + + segs = segs[1:] + startPort2, endPort2, proto2, err := parsePortRange(segs[0]) + if err != nil { + return fmt.Errorf("invalid port range2 %s, err %v", segs[0], err) + } + if proto2 != proto { + return fmt.Errorf("protocol mismatch in hash:net,port,net,port member") + } + param.GetAddrRange2().SetMinPort(startPort2) + if endPort2 > 0 { + param.GetAddrRange2().SetMaxPort(endPort2) + } else { + param.GetAddrRange2().SetMaxPort(startPort2) + } + + return nil +} + +func (o *IPSetHashNetPortNetPort) ModelEntry(af uint8, member *IPSetMember) (*models.IpsetMember, error) { + model := &models.IpsetMember{} + + proto := protoString(member.GetProto()) + entry := fmt.Sprintf("%s/%d,%s:%d,%s/%d,%s:%d", + member.GetAddr(af).String(), + member.GetCidr(), + proto, member.GetPort(), + member.GetAddr2(af).String(), + member.GetCidr2(), + proto, member.GetPort2()) + model.Entry = &entry + + return model, nil +} + +func (o *IPSetHashNetPortNetPort) CheckParam(param *IPSetParam) error { + // nothing to do + return nil +} + +var ipsetTypes = map[models.IpsetType]IPSetType{ + models.IpsetTypeBitmapIP: &IPSetBitmapIP{}, + models.IpsetTypeBitmapIPMac: &IPSetBitmapIPMac{}, + models.IpsetTypeBitmapPort: &IPSetBitmapPort{}, + models.IpsetTypeHashIP: &IPSetHashIP{}, + models.IpsetTypeHashNet: &IPSetHashNet{}, + models.IpsetTypeHashIPPort: &IPSetHashIPPort{}, + models.IpsetTypeHashNetPort: &IPSetHashNetPort{}, + models.IpsetTypeHashNetPortIface: &IPSetHashNetPortIface{}, + models.IpsetTypeHashIPPortIP: &IPSetHashIPPortIP{}, + models.IpsetTypeHashIPPortNet: &IPSetHashIPPortNet{}, + models.IpsetTypeHashNetPortNet: &IPSetHashNetPortNet{}, + models.IpsetTypeHashNetPortNetPort: &IPSetHashNetPortNetPort{}, +} + +func IPSetTypeGet(kind models.IpsetType) IPSetType { + return ipsetTypes[kind] +} + +func afCode(family string) uint8 { + switch strings.ToLower(family) { + case "": + return syscall.AF_UNSPEC + case "ipv4": + return syscall.AF_INET + case "ipv6": + return syscall.AF_INET6 + default: + return syscall.AF_MAX + } +} + +func afString(af uint8) string { + switch af { + case syscall.AF_INET: + return "ipv4" + case syscall.AF_INET6: + return "ipv6" + default: + return "not-supported" + } +} + +func protoString(proto uint8) string { + switch proto { + case syscall.IPPROTO_TCP: + return "tcp" + case syscall.IPPROTO_UDP: + return "udp" + case syscall.IPPROTO_ICMP: + return "icmp" + case syscall.IPPROTO_ICMPV6: + return "icmp6" + } + return "unspec" +} + +func ip4ToUint32(ip net.IP) uint32 { + ip4 := ip.To4() + if ip4 == nil { + return 0 + } + return binary.BigEndian.Uint32(ip4) +} + +// Parse IP range +// Format: +// +// { IPv4 | IPv4-IPv4 | IPv4/pfx4 | IPv6 | IPv6/pfx6 } +// +// Example: +// - 192.168.1.0/24 +// - 192.168.88.100-120 +// - 2001::/112 +func parseAddrRange(ar string) (startIP, endIP net.IP, af, cidr uint8, err error) { + if strings.Contains(ar, ":") { + af = syscall.AF_INET6 + } else { + af = syscall.AF_INET + } + + if af == syscall.AF_INET { + if strings.Contains(ar, "-") { + parts := strings.Split(ar, "-") + if len(parts) != 2 { + err = fmt.Errorf("invalid IPv4 range format %q", ar) + return + } + startIP = net.ParseIP(parts[0]).To4() + endIP = net.ParseIP(parts[1]).To4() + if startIP == nil || endIP == nil { + err = fmt.Errorf("invalid IPv4 address %q", ar) + return + } + if ip4ToUint32(startIP) > ip4ToUint32(endIP) { + err = fmt.Errorf("invalid IPv4 range %q", ar) + return + } + } else if strings.Contains(ar, "/") { + ip, ipNet, err2 := net.ParseCIDR(ar) + if err2 != nil { + err = fmt.Errorf("invalid IPv4 CIDR format: %v", err2) + return + } + startIP = ip.To4() + pfx, _ := ipNet.Mask.Size() + cidr = uint8(pfx) + } else { + if startIP = net.ParseIP(ar); startIP != nil { + startIP = startIP.To4() + } + if startIP == nil { + err = fmt.Errorf("unsupported IPv4 format") + return + } + } + } else { // syscall.AF_INET6 + if strings.Contains(ar, "/") { + ip, ipNet, err2 := net.ParseCIDR(ar) + if err2 != nil { + err = fmt.Errorf("invalid IPv6 CIDR format: %v", err2) + return + } + startIP = ip.To16() + pfx, _ := ipNet.Mask.Size() + cidr = uint8(pfx) + } else { + startIP = net.ParseIP(ar) + if startIP == nil { + err = fmt.Errorf("unsupported IPv6 format") + return + } + } + } + + return +} + +// Format: +// +// PROTO:PORT[-PORT] +// PROTO := tcp | udp | icmp | icmp6 +// PORT := NUM(0-65535) +// +// Example: +// +// tcp:8080-8082 +func parsePortRange(pr string) (port1, port2 uint16, proto uint8, err error) { + parts := strings.Split(pr, ":") + if len(parts) > 2 { + err = fmt.Errorf("too many segments in %q", pr) + return + } + + if len(parts) > 1 { + protoStr := strings.ToLower(parts[0]) + switch protoStr { + case "tcp": + proto = syscall.IPPROTO_TCP + case "udp": + proto = syscall.IPPROTO_UDP + case "icmp": + proto = syscall.IPPROTO_ICMP + case "icmp6": + proto = syscall.IPPROTO_ICMPV6 + default: + err = fmt.Errorf("invalid protocol %q", protoStr) + return + } + parts = parts[1:] + } + + portRange := parts[0] + parts = strings.Split(portRange, "-") + if len(parts) > 2 { + err = fmt.Errorf("too many segments in port range %q", portRange) + return + } + + _port1, err := strconv.ParseUint(parts[0], 10, 16) + if err != nil { + err = fmt.Errorf("invalid port number %q", parts[0]) + return + } + port1 = uint16(_port1) + + if len(parts) > 1 { + var _port2 uint64 + _port2, err = strconv.ParseUint(parts[1], 10, 16) + if err != nil { + err = fmt.Errorf("invalid port number %q", parts[1]) + return + } + port2 = uint16(_port2) + } + return +} + +func (o *IPSetParam) Build(model *models.IpsetInfo) error { + if len(model.Entries) > 0 && model.CreationOptions != nil { + return fmt.Errorf("Entries and CreationOptions cannot both set") + } + if len(model.Entries) > 1 { + return fmt.Errorf("More than 1 entry set for IPSetParam") + } + + o.SetName(*model.Name) + o.SetKind(string(*model.Type)) + + if model.CreationOptions != nil { + options := model.CreationOptions + if options.Comment != nil { + o.SetCommentFlag(*options.Comment) + } + o.SetMaxElem(options.HashMaxElem) + o.SetHashSize(options.HashSize) + af := afCode(options.Family) + if af == syscall.AF_MAX { + return fmt.Errorf("Unsupported address family %q", options.Family) + } + o.SetAf(af) + if len(options.Range) > 0 { + if strings.ContainsAny(options.Range, ".:") && unicode.Is(unicode.ASCII_Hex_Digit, + rune(options.Range[0])) { // IPv4 or IPv6 + startIP, endIP, af2, pfx, err := parseAddrRange(options.Range) + if err != nil { + return err + } + if af2 != af { + if af == syscall.AF_UNSPEC { + o.SetAf(af2) + } else { + return fmt.Errorf("Address family mismatch") + } + } + o.GetAddrRange().SetMinAddr(startIP) + if endIP != nil { + o.GetAddrRange().SetMaxAddr(endIP) + } + if pfx > 0 { + o.SetCidr(pfx) + } + } else { // Port + startPort, endPort, proto, err := parsePortRange(options.Range) + if err != nil { + return err + } + o.GetAddrRange().SetMinPort(startPort) + if endPort != 0 { + o.GetAddrRange().SetMaxPort(endPort) + } else { + o.GetAddrRange().SetMaxPort(startPort) + } + o.SetProto(proto) + } + } + } + + if len(model.Entries) > 0 { + return o.BuildMember(model.Entries[0]) + } + return nil +} + +func (o *IPSetParamArray) Build(opcode uint16, model *models.IpsetInfo) error { + if opcode == IPSET_OP_FLUSH { + param := new(IPSetParam) + param.SetOpcode(opcode) + param.SetName(*model.Name) + param.SetKind(string(*model.Type)) + *o = append(*o, *param) + return nil + } + + if len(model.Entries) < 1 { + return fmt.Errorf("No Entries found in IpsetInfo model") + } + if model.CreationOptions != nil { + return fmt.Errorf("CreationOptions supplied with multiple Entries") + } + + for _, entry := range model.Entries { + param := new(IPSetParam) + param.SetOpcode(opcode) + param.SetName(*model.Name) + param.SetKind(string(*model.Type)) + err := param.BuildMember(entry) + if err != nil { + return fmt.Errorf("Parse ipset member %v failed: %v", entry.Entry, err) + } + *o = append(*o, *param) + } + return nil +} + +// o.kind must be filled before calling BuildMember +func (o *IPSetParam) BuildMember(model *models.IpsetMember) error { + kind := o.getKind() + setType := IPSetTypeGet(models.IpsetType(kind)) + if setType == nil { + return fmt.Errorf("Unsupported ipset type %q", kind) + } + + if model.Entry == nil { + return fmt.Errorf("Empty ipset member entry") + } + + o.SetComment(model.Comment) + if model.Options != nil { + if model.Options.Force != nil && *model.Options.Force { + o.AddFlag(IPSET_F_FORCE) + } else { + o.DelFlag(IPSET_F_FORCE) + } + if model.Options.NoMatch != nil { + o.SetNomatch(*model.Options.NoMatch) + } + } + + return setType.ParseEntry(*model.Entry, o) +} + +func (o *IPSetParam) Check() error { + if o.opcode >= IPSET_OP_MAX { + return fmt.Errorf("Invalid ipset opcode %v", o.opcode) + } else if o.opcode == IPSET_OP_LIST { + return nil + } else if o.opcode == IPSET_OP_TEST { + if o.cidr > 0 || o.cidr2 > 0 { + return fmt.Errorf("Cidr set in IPSET_OP_TEST (IsIn)") + } + } + + kind := o.getKind() + setType := IPSetTypeGet(models.IpsetType(kind)) + if setType == nil { + return fmt.Errorf("Unsupported ipset type %q", kind) + } + + startIP1, endIP1, startPort1, endPort1 := o.addrRange.Decode(o.af) + startIP2, endIP2, startPort2, endPort2 := o.addrRange2.Decode(o.af) + if o.af == syscall.AF_INET6 { + if !endIP1.Equal(net.IPv6zero) && !endIP1.Equal(startIP1) { + return fmt.Errorf("IPv6 range is not supported") + } + if !endIP2.Equal(net.IPv6zero) && !endIP2.Equal(startIP2) { + return fmt.Errorf("IPv6 range is not supported") + } + } else if o.af == syscall.AF_INET { + start, end := ip4ToUint32(startIP1), ip4ToUint32(endIP1) + if end != 0 && start > end { + return fmt.Errorf("Invalid IPv4 range: %v-%v", startIP1, endIP1) + } + start, end = ip4ToUint32(startIP2), ip4ToUint32(endIP2) + if end != 0 && start > end { + return fmt.Errorf("Invalid IPv4 range: %v-%v", startIP2, endIP2) + } + } + + if endPort1 > 0 && startPort1 > endPort1 { + return fmt.Errorf("Invalid port range: %d-%d", startPort1, endPort1) + } + + if endPort2 > 0 && startPort2 > endPort2 { + return fmt.Errorf("Invalid port range: %d-%d", startPort2, endPort2) + } + + return setType.CheckParam(o) +} + +func (o *IPSetParamArray) Check() error { + for _, param := range *o { + if err := param.Check(); err != nil { + return err + } + } + return nil +} + +func (o *IPSetMember) Model(af uint8, kind models.IpsetType) (*models.IpsetMember, error) { + setType := IPSetTypeGet(kind) + if setType == nil { + return nil, fmt.Errorf("Unsupported ipset type %q", kind) + } + + model, err := setType.ModelEntry(af, o) + if err != nil { + return nil, err + } + + model.Comment = o.GetComment() + nomatch := o.GetNoMatch() + if nomatch { + model.Options = &models.IpsetOption{} + model.Options.NoMatch = &nomatch + } + return model, nil +} + +func (o *IPSetInfo) Model() (*models.IpsetInfo, error) { + model := new(models.IpsetInfo) + model.Name = new(string) + model.Type = new(models.IpsetType) + model.CreationOptions = new(models.IpsetCreationOption) + + *model.Name = o.GetName() + *model.Type = models.IpsetType(o.GetKind()) + model.Opcode = IPSET_OP_LIST + + af := o.GetAf() + cidr := o.GetCidr() + withIP := false + + copts := model.CreationOptions + if o.GetComment() { + copts.Comment = new(bool) + *copts.Comment = true + } + copts.Family = afString(af) + if strings.HasPrefix(string(*model.Type), "hash:") { + copts.HashMaxElem = o.GetHashMaxElem() + copts.HashSize = o.GetHashSize() + } else if strings.HasPrefix(string(*model.Type), "bitmap:") { + copts.Range = "" + startIP, endIP, startPort, endPort := o.GetAddrRange() + if cidr > 0 { + copts.Range += fmt.Sprintf("%s/%d", startIP, cidr) + withIP = true + } else if af == syscall.AF_INET { + startIPNum, endIPNum := ip4ToUint32(startIP), ip4ToUint32(endIP) + if endIPNum > startIPNum { + copts.Range += fmt.Sprintf("%s-%s", startIP.String(), endIP.String()) + withIP = true + } + } + if endPort > startPort { + if withIP { + copts.Range += ":" + } + copts.Range += fmt.Sprintf("%d-%d", startPort, endPort) + } + } + + for _, member := range o.GetMembers() { + memberModel, err := member.Model(af, *model.Type) + if err != nil { + return nil, err + } + model.Entries = append(model.Entries, memberModel) + } + + return model, nil +} + +func (o *IPSetInfoArray) Model() (*models.IpsetInfoArray, error) { + model := new(models.IpsetInfoArray) + for _, info := range o.GetIPSetInfos() { + infoModel, err := info.Model() + if err != nil { + return nil, err + } + model.Infos = append(model.Infos, infoModel) + } + model.Count = int32(len(model.Infos)) + + return model, nil +} diff --git a/tools/dpvs-agent/restapi/embedded_spec.go b/tools/dpvs-agent/restapi/embedded_spec.go index e16e252cf..323f0a90c 100644 --- a/tools/dpvs-agent/restapi/embedded_spec.go +++ b/tools/dpvs-agent/restapi/embedded_spec.go @@ -268,7 +268,7 @@ func init() { "tags": [ "device" ], - "summary": "ip addr add 10.0.0.1/32 dev eth0: Set ip cird to linux net device", + "summary": "ip addr add 10.0.0.1/32 dev eth0: Set ip cird to linux net device\n", "parameters": [ { "$ref": "#/parameters/snapshot" @@ -299,7 +299,7 @@ func init() { "tags": [ "device" ], - "summary": "ip addr del 10.0.0.1/32 dev eth0: Delete ip cird fron linux net device", + "summary": "ip addr del 10.0.0.1/32 dev eth0: Delete ip cird fron linux net device\n", "parameters": [ { "$ref": "#/parameters/device-name" @@ -360,7 +360,7 @@ func init() { "tags": [ "device" ], - "summary": "dpip link set ${nic-name} [forward2kni,link,promisc,tc-ingress,tc-egress] [on/up,off/down]", + "summary": "dpip link set ${nic-name} [forward2kni,link,promisc,tc-ingress,tc-egress] [on/up,off/down]\n", "parameters": [ { "$ref": "#/parameters/device-name" @@ -566,6 +566,335 @@ func init() { } } }, + "/ipset": { + "get": { + "tags": [ + "ipset" + ], + "summary": "Get all the ipsets and members.", + "operationId": "GetAll", + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/IpsetInfoArray" + } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" + } + } + } + }, + "/ipset/{name}": { + "get": { + "tags": [ + "ipset" + ], + "summary": "Get a specific ipset and its members.", + "operationId": "Get", + "parameters": [ + { + "$ref": "#/parameters/ipset-name" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/IpsetInfo" + } + }, + "404": { + "description": "Ipset not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" + } + } + }, + "put": { + "tags": [ + "ipset" + ], + "summary": "Create an ipset named {name}.", + "operationId": "Create", + "parameters": [ + { + "$ref": "#/parameters/ipset-name" + }, + { + "$ref": "#/parameters/ipset-param" + } + ], + "responses": { + "200": { + "description": "Replaced", + "schema": { + "type": "string" + } + }, + "201": { + "description": "Created", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Invalid ipset parameter", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Ipset not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" + } + } + }, + "delete": { + "tags": [ + "ipset" + ], + "summary": "Delete the ipset named {name}.", + "operationId": "Destroy", + "parameters": [ + { + "$ref": "#/parameters/ipset-name" + } + ], + "responses": { + "200": { + "description": "Deleted", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Ipset not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" + } + } + } + }, + "/ipset/{name}/cell": { + "post": { + "tags": [ + "ipset" + ], + "summary": "Check if an object in the ipset.", + "operationId": "IsIn", + "parameters": [ + { + "$ref": "#/parameters/ipset-name" + }, + { + "$ref": "#/parameters/ipset-cell" + } + ], + "responses": { + "200": { + "description": "Succeed", + "schema": { + "type": "object", + "required": [ + "Result" + ], + "properties": { + "Message": { + "type": "string" + }, + "Result": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Invalid ipset parameter", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Ipset not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" + } + } + } + }, + "/ipset/{name}/member": { + "put": { + "tags": [ + "ipset" + ], + "summary": "Reset the whole ipset members.", + "operationId": "ReplaceMember", + "parameters": [ + { + "$ref": "#/parameters/ipset-name" + }, + { + "$ref": "#/parameters/ipset-param" + } + ], + "responses": { + "200": { + "description": "Succeed", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Invalid ipset parameter", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Ipset not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" + } + } + }, + "post": { + "tags": [ + "ipset" + ], + "summary": "Add members to the ipset.", + "operationId": "AddMember", + "parameters": [ + { + "$ref": "#/parameters/ipset-name" + }, + { + "$ref": "#/parameters/ipset-param" + } + ], + "responses": { + "200": { + "description": "Existed", + "schema": { + "type": "string" + } + }, + "201": { + "description": "Created", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Invalid ipset parameter", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Ipset not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" + } + } + }, + "delete": { + "tags": [ + "ipset" + ], + "summary": "Delete members from the ipset.", + "operationId": "DelMember", + "parameters": [ + { + "$ref": "#/parameters/ipset-name" + }, + { + "$ref": "#/parameters/ipset-param" + } + ], + "responses": { + "200": { + "description": "Succeed", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Invalid ipset parameter", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Ipset not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" + } + } + } + }, "/vs": { "get": { "tags": [ @@ -1386,7 +1715,7 @@ func init() { "description": "Success" }, "270": { - "description": "the rss-config parameter is outdated, update nothing and return the latest rs info", + "description": "the rss-config parameter is outdated, update nothing and return the latest rs info\n", "schema": { "$ref": "#/definitions/VirtualServerSpecExpand" }, @@ -1444,6 +1773,9 @@ func init() { "properties": { "addr": { "type": "string" + }, + "ipset": { + "type": "string" } } }, @@ -1480,11 +1812,176 @@ func init() { "broadcast": { "type": "string" }, - "scope": { - "type": "string" + "scope": { + "type": "string" + } + } + }, + "IpsetCell": { + "description": "IpsetCell represents an indivisible granularity of ipset member.", + "type": "object", + "required": [ + "Type", + "Member" + ], + "properties": { + "Member": { + "$ref": "#/definitions/IpsetMember" + }, + "Type": { + "$ref": "#/definitions/IpsetType" + } + } + }, + "IpsetCreationOption": { + "description": "IpsetCreationOption contains all available options required in creating an ipset.\n", + "properties": { + "Comment": { + "type": "boolean", + "default": false + }, + "Family": { + "type": "string", + "enum": [ + "ipv4", + "ipv6" + ] + }, + "HashMaxElem": { + "type": "integer", + "format": "uint32" + }, + "HashSize": { + "type": "integer", + "format": "uint32" + }, + "Range": { + "description": "vaild format: ipv4-ipv4, ipv4/pfx, ipv6/pfx, port-port\n", + "type": "string" + } + } + }, + "IpsetInfo": { + "description": "IpsetInfo contains all parameters and information for ipset operations.\n", + "type": "object", + "required": [ + "Type", + "Name" + ], + "properties": { + "CreationOptions": { + "$ref": "#/definitions/IpsetCreationOption" + }, + "Entries": { + "type": "array", + "items": { + "$ref": "#/definitions/IpsetMember" + } + }, + "Name": { + "type": "string", + "maxLength": 32, + "minLength": 1 + }, + "Opcode": { + "description": "opertaion type code", + "type": "integer", + "format": "uint16", + "enum": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "x-enum-varnames": [ + "Add", + "Del", + "Test", + "Create", + "Destroy", + "Flush", + "List" + ] + }, + "Type": { + "type": "string", + "$ref": "#/definitions/IpsetType" + } + } + }, + "IpsetInfoArray": { + "description": "IpsetInfoArray contains an array of ipset.", + "type": "object", + "properties": { + "Count": { + "type": "integer", + "format": "int32" + }, + "Infos": { + "type": "array", + "items": { + "$ref": "#/definitions/IpsetInfo" + } + } + } + }, + "IpsetMember": { + "description": "IpsetMember represents a specific entry in ipset.", + "type": "object", + "required": [ + "Entry" + ], + "properties": { + "Comment": { + "type": "string", + "maxLength": 32, + "minLength": 1 + }, + "Entry": { + "description": "type specific entry data, for example\n* 192.168.1.0/29 (bitmap:ip)\n* 192.168.88.0/24,tcp:8080-8082 (hash:net)\n* 2001::1,8080-8082,2002::aaaa:bbbb:ccc0:0/108 (hash:ip,port,net)\n", + "type": "string" + }, + "Options": { + "$ref": "#/definitions/IpsetOption" + } + } + }, + "IpsetOption": { + "description": "IpsetOption defines common options for ipset operations.", + "type": "object", + "properties": { + "Force": { + "description": "When add members to ipset with Force set, the already existing members are replaced sliently instead of emitting an EDPVS_EXIST error; When delete non-existent memebers from ipset, the DPSVS_NOTEXIST error is ignored.\n", + "type": "boolean", + "default": false + }, + "NoMatch": { + "description": "Nomatch excludes a small element range from an ipset, which is mainly used by network-cidr based ipset.\n", + "type": "boolean", + "default": false } } }, + "IpsetType": { + "type": "string", + "enum": [ + "bitmap:ip", + "bitmap:ip,mac", + "bitmap:port", + "hash:ip", + "hash:net", + "hash:ip,port", + "hash:net,port", + "hash:net,port,iface", + "hash:ip,port,ip", + "hash:ip,port,net", + "hash:net,port,net", + "hash:net,port,net,port" + ] + }, "LocalAddressExpandList": { "properties": { "Items": { @@ -2135,6 +2632,26 @@ func init() { "name": "healthcheck", "in": "query" }, + "ipset-cell": { + "name": "ipsetCell", + "in": "body", + "schema": { + "$ref": "#/definitions/IpsetCell" + } + }, + "ipset-name": { + "type": "string", + "name": "name", + "in": "path", + "required": true + }, + "ipset-param": { + "name": "ipsetParam", + "in": "body", + "schema": { + "$ref": "#/definitions/IpsetInfo" + } + }, "laddr-config": { "name": "spec", "in": "body", @@ -2274,6 +2791,10 @@ func init() { { "description": "arp", "name": "arp" + }, + { + "description": "ipset", + "name": "ipset" } ] }`)) @@ -2581,7 +3102,7 @@ func init() { "tags": [ "device" ], - "summary": "ip addr add 10.0.0.1/32 dev eth0: Set ip cird to linux net device", + "summary": "ip addr add 10.0.0.1/32 dev eth0: Set ip cird to linux net device\n", "parameters": [ { "type": "boolean", @@ -2622,7 +3143,7 @@ func init() { "tags": [ "device" ], - "summary": "ip addr del 10.0.0.1/32 dev eth0: Delete ip cird fron linux net device", + "summary": "ip addr del 10.0.0.1/32 dev eth0: Delete ip cird fron linux net device\n", "parameters": [ { "type": "string", @@ -2699,7 +3220,7 @@ func init() { "tags": [ "device" ], - "summary": "dpip link set ${nic-name} [forward2kni,link,promisc,tc-ingress,tc-egress] [on/up,off/down]", + "summary": "dpip link set ${nic-name} [forward2kni,link,promisc,tc-ingress,tc-egress] [on/up,off/down]\n", "parameters": [ { "type": "string", @@ -2752,24 +3273,254 @@ func init() { "description": "Failure", "schema": { "type": "string" - } + } + } + } + } + }, + "/device/{name}/route": { + "get": { + "tags": [ + "device" + ], + "summary": "display special net device route", + "parameters": [ + { + "type": "boolean", + "default": false, + "name": "stats", + "in": "query" + }, + { + "type": "string", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "string" + } + } + } + }, + "put": { + "tags": [ + "device" + ], + "summary": "add/update special net device route", + "parameters": [ + { + "type": "string", + "name": "name", + "in": "path", + "required": true + }, + { + "name": "spec", + "in": "body", + "schema": { + "$ref": "#/definitions/RouteSpec" + } + } + ], + "responses": { + "200": { + "description": "Update exist route Success", + "schema": { + "type": "string" + } + }, + "201": { + "description": "Add new route Success", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Failed", + "schema": { + "type": "string" + } + } + } + }, + "delete": { + "tags": [ + "device" + ], + "summary": "delete special net device route", + "parameters": [ + { + "type": "string", + "name": "name", + "in": "path", + "required": true + }, + { + "name": "spec", + "in": "body", + "schema": { + "$ref": "#/definitions/RouteSpec" + } + } + ], + "responses": { + "200": { + "description": "delete route Success", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Failed", + "schema": { + "type": "string" + } + } + } + } + }, + "/device/{name}/vlan": { + "get": { + "tags": [ + "device" + ], + "summary": "display all net device list", + "parameters": [ + { + "type": "string", + "name": "name", + "in": "path", + "required": true + }, + { + "type": "boolean", + "default": false, + "name": "stats", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "string" + } + } + } + }, + "put": { + "tags": [ + "device" + ], + "summary": "add/update special net device ", + "parameters": [ + { + "type": "string", + "name": "name", + "in": "path", + "required": true + }, + { + "name": "spec", + "in": "body", + "schema": { + "$ref": "#/definitions/VlanSpec" + } + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Failed", + "schema": { + "type": "string" + } + } + } + }, + "delete": { + "tags": [ + "device" + ], + "summary": "delete special net device", + "parameters": [ + { + "type": "string", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Failed", + "schema": { + "type": "string" + } + } + } + } + }, + "/ipset": { + "get": { + "tags": [ + "ipset" + ], + "summary": "Get all the ipsets and members.", + "operationId": "GetAll", + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/IpsetInfoArray" + } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" } } } }, - "/device/{name}/route": { + "/ipset/{name}": { "get": { "tags": [ - "device" + "ipset" ], - "summary": "display special net device route", + "summary": "Get a specific ipset and its members.", + "operationId": "Get", "parameters": [ - { - "type": "boolean", - "default": false, - "name": "stats", - "in": "query" - }, { "type": "string", "name": "name", @@ -2781,22 +3532,30 @@ func init() { "200": { "description": "Success", "schema": { - "type": "string" + "$ref": "#/definitions/IpsetInfo" } }, "404": { - "description": "Not Found", + "description": "Ipset not found", "schema": { "type": "string" } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" } } }, "put": { "tags": [ - "device" + "ipset" ], - "summary": "add/update special net device route", + "summary": "Create an ipset named {name}.", + "operationId": "Create", "parameters": [ { "type": "string", @@ -2805,39 +3564,91 @@ func init() { "required": true }, { - "name": "spec", + "name": "ipsetParam", "in": "body", "schema": { - "$ref": "#/definitions/RouteSpec" + "$ref": "#/definitions/IpsetInfo" } } ], "responses": { "200": { - "description": "Update exist route Success", + "description": "Replaced", "schema": { "type": "string" } }, "201": { - "description": "Add new route Success", + "description": "Created", "schema": { "type": "string" } }, - "500": { - "description": "Failed", + "400": { + "description": "Invalid ipset parameter", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Ipset not found", "schema": { "type": "string" } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" } } }, "delete": { "tags": [ - "device" + "ipset" ], - "summary": "delete special net device route", + "summary": "Delete the ipset named {name}.", + "operationId": "Destroy", + "parameters": [ + { + "type": "string", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Deleted", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Ipset not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" + } + } + } + }, + "/ipset/{name}/cell": { + "post": { + "tags": [ + "ipset" + ], + "summary": "Check if an object in the ipset.", + "operationId": "IsIn", "parameters": [ { "type": "string", @@ -2846,35 +3657,60 @@ func init() { "required": true }, { - "name": "spec", + "name": "ipsetCell", "in": "body", "schema": { - "$ref": "#/definitions/RouteSpec" + "$ref": "#/definitions/IpsetCell" } } ], "responses": { "200": { - "description": "delete route Success", + "description": "Succeed", + "schema": { + "type": "object", + "required": [ + "Result" + ], + "properties": { + "Message": { + "type": "string" + }, + "Result": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Invalid ipset parameter", "schema": { "type": "string" } }, - "500": { - "description": "Failed", + "404": { + "description": "Ipset not found", "schema": { "type": "string" } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" } } } }, - "/device/{name}/vlan": { - "get": { + "/ipset/{name}/member": { + "put": { "tags": [ - "device" + "ipset" ], - "summary": "display all net device list", + "summary": "Reset the whole ipset members.", + "operationId": "ReplaceMember", "parameters": [ { "type": "string", @@ -2883,32 +3719,47 @@ func init() { "required": true }, { - "type": "boolean", - "default": false, - "name": "stats", - "in": "query" + "name": "ipsetParam", + "in": "body", + "schema": { + "$ref": "#/definitions/IpsetInfo" + } } ], "responses": { "200": { - "description": "Success", + "description": "Succeed", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Invalid ipset parameter", "schema": { "type": "string" } }, "404": { - "description": "Not Found", + "description": "Ipset not found", "schema": { "type": "string" } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" } } }, - "put": { + "post": { "tags": [ - "device" + "ipset" ], - "summary": "add/update special net device ", + "summary": "Add members to the ipset.", + "operationId": "AddMember", "parameters": [ { "type": "string", @@ -2917,53 +3768,93 @@ func init() { "required": true }, { - "name": "spec", + "name": "ipsetParam", "in": "body", "schema": { - "$ref": "#/definitions/VlanSpec" + "$ref": "#/definitions/IpsetInfo" } } ], "responses": { "200": { - "description": "Success", + "description": "Existed", "schema": { "type": "string" } }, - "500": { - "description": "Failed", + "201": { + "description": "Created", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Invalid ipset parameter", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Ipset not found", "schema": { "type": "string" } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" } } }, "delete": { "tags": [ - "device" + "ipset" ], - "summary": "delete special net device", + "summary": "Delete members from the ipset.", + "operationId": "DelMember", "parameters": [ { "type": "string", "name": "name", "in": "path", "required": true + }, + { + "name": "ipsetParam", + "in": "body", + "schema": { + "$ref": "#/definitions/IpsetInfo" + } } ], "responses": { "200": { - "description": "Success", + "description": "Succeed", "schema": { "type": "string" } }, - "500": { - "description": "Failed", + "400": { + "description": "Invalid ipset parameter", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Ipset not found", "schema": { "type": "string" } + }, + "500": { + "description": "Service not available", + "schema": { + "type": "string" + }, + "x-go-name": "Failure" } } } @@ -3939,7 +4830,7 @@ func init() { "description": "Success" }, "270": { - "description": "the rss-config parameter is outdated, update nothing and return the latest rs info", + "description": "the rss-config parameter is outdated, update nothing and return the latest rs info\n", "schema": { "$ref": "#/definitions/VirtualServerSpecExpand" }, @@ -3997,6 +4888,9 @@ func init() { "properties": { "addr": { "type": "string" + }, + "ipset": { + "type": "string" } } }, @@ -4038,6 +4932,171 @@ func init() { } } }, + "IpsetCell": { + "description": "IpsetCell represents an indivisible granularity of ipset member.", + "type": "object", + "required": [ + "Type", + "Member" + ], + "properties": { + "Member": { + "$ref": "#/definitions/IpsetMember" + }, + "Type": { + "$ref": "#/definitions/IpsetType" + } + } + }, + "IpsetCreationOption": { + "description": "IpsetCreationOption contains all available options required in creating an ipset.\n", + "properties": { + "Comment": { + "type": "boolean", + "default": false + }, + "Family": { + "type": "string", + "enum": [ + "ipv4", + "ipv6" + ] + }, + "HashMaxElem": { + "type": "integer", + "format": "uint32" + }, + "HashSize": { + "type": "integer", + "format": "uint32" + }, + "Range": { + "description": "vaild format: ipv4-ipv4, ipv4/pfx, ipv6/pfx, port-port\n", + "type": "string" + } + } + }, + "IpsetInfo": { + "description": "IpsetInfo contains all parameters and information for ipset operations.\n", + "type": "object", + "required": [ + "Type", + "Name" + ], + "properties": { + "CreationOptions": { + "$ref": "#/definitions/IpsetCreationOption" + }, + "Entries": { + "type": "array", + "items": { + "$ref": "#/definitions/IpsetMember" + } + }, + "Name": { + "type": "string", + "maxLength": 32, + "minLength": 1 + }, + "Opcode": { + "description": "opertaion type code", + "type": "integer", + "format": "uint16", + "enum": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "x-enum-varnames": [ + "Add", + "Del", + "Test", + "Create", + "Destroy", + "Flush", + "List" + ] + }, + "Type": { + "type": "string", + "$ref": "#/definitions/IpsetType" + } + } + }, + "IpsetInfoArray": { + "description": "IpsetInfoArray contains an array of ipset.", + "type": "object", + "properties": { + "Count": { + "type": "integer", + "format": "int32" + }, + "Infos": { + "type": "array", + "items": { + "$ref": "#/definitions/IpsetInfo" + } + } + } + }, + "IpsetMember": { + "description": "IpsetMember represents a specific entry in ipset.", + "type": "object", + "required": [ + "Entry" + ], + "properties": { + "Comment": { + "type": "string", + "maxLength": 32, + "minLength": 1 + }, + "Entry": { + "description": "type specific entry data, for example\n* 192.168.1.0/29 (bitmap:ip)\n* 192.168.88.0/24,tcp:8080-8082 (hash:net)\n* 2001::1,8080-8082,2002::aaaa:bbbb:ccc0:0/108 (hash:ip,port,net)\n", + "type": "string" + }, + "Options": { + "$ref": "#/definitions/IpsetOption" + } + } + }, + "IpsetOption": { + "description": "IpsetOption defines common options for ipset operations.", + "type": "object", + "properties": { + "Force": { + "description": "When add members to ipset with Force set, the already existing members are replaced sliently instead of emitting an EDPVS_EXIST error; When delete non-existent memebers from ipset, the DPSVS_NOTEXIST error is ignored.\n", + "type": "boolean", + "default": false + }, + "NoMatch": { + "description": "Nomatch excludes a small element range from an ipset, which is mainly used by network-cidr based ipset.\n", + "type": "boolean", + "default": false + } + } + }, + "IpsetType": { + "type": "string", + "enum": [ + "bitmap:ip", + "bitmap:ip,mac", + "bitmap:port", + "hash:ip", + "hash:net", + "hash:ip,port", + "hash:net,port", + "hash:net,port,iface", + "hash:ip,port,ip", + "hash:ip,port,net", + "hash:net,port,net", + "hash:net,port,net,port" + ] + }, "LocalAddressExpandList": { "properties": { "Items": { @@ -4688,6 +5747,26 @@ func init() { "name": "healthcheck", "in": "query" }, + "ipset-cell": { + "name": "ipsetCell", + "in": "body", + "schema": { + "$ref": "#/definitions/IpsetCell" + } + }, + "ipset-name": { + "type": "string", + "name": "name", + "in": "path", + "required": true + }, + "ipset-param": { + "name": "ipsetParam", + "in": "body", + "schema": { + "$ref": "#/definitions/IpsetInfo" + } + }, "laddr-config": { "name": "spec", "in": "body", @@ -4827,6 +5906,10 @@ func init() { { "description": "arp", "name": "arp" + }, + { + "description": "ipset", + "name": "ipset" } ] }`)) diff --git a/tools/dpvs-agent/restapi/operations/dpvs_agent_api.go b/tools/dpvs-agent/restapi/operations/dpvs_agent_api.go index 8f292b4ba..ec6c9bf3c 100644 --- a/tools/dpvs-agent/restapi/operations/dpvs_agent_api.go +++ b/tools/dpvs-agent/restapi/operations/dpvs_agent_api.go @@ -20,6 +20,7 @@ import ( "github.com/go-openapi/swag" "github.com/dpvs-agent/restapi/operations/device" + "github.com/dpvs-agent/restapi/operations/ipset" "github.com/dpvs-agent/restapi/operations/virtualserver" ) @@ -45,6 +46,15 @@ func NewDpvsAgentAPI(spec *loads.Document) *DpvsAgentAPI { JSONProducer: runtime.JSONProducer(), + IpsetAddMemberHandler: ipset.AddMemberHandlerFunc(func(params ipset.AddMemberParams) middleware.Responder { + return middleware.NotImplemented("operation ipset.AddMember has not yet been implemented") + }), + IpsetCreateHandler: ipset.CreateHandlerFunc(func(params ipset.CreateParams) middleware.Responder { + return middleware.NotImplemented("operation ipset.Create has not yet been implemented") + }), + IpsetDelMemberHandler: ipset.DelMemberHandlerFunc(func(params ipset.DelMemberParams) middleware.Responder { + return middleware.NotImplemented("operation ipset.DelMember has not yet been implemented") + }), DeviceDeleteDeviceNameAddrHandler: device.DeleteDeviceNameAddrHandlerFunc(func(params device.DeleteDeviceNameAddrParams) middleware.Responder { return middleware.NotImplemented("operation device.DeleteDeviceNameAddr has not yet been implemented") }), @@ -75,6 +85,15 @@ func NewDpvsAgentAPI(spec *loads.Document) *DpvsAgentAPI { VirtualserverDeleteVsVipPortRsHandler: virtualserver.DeleteVsVipPortRsHandlerFunc(func(params virtualserver.DeleteVsVipPortRsParams) middleware.Responder { return middleware.NotImplemented("operation virtualserver.DeleteVsVipPortRs has not yet been implemented") }), + IpsetDestroyHandler: ipset.DestroyHandlerFunc(func(params ipset.DestroyParams) middleware.Responder { + return middleware.NotImplemented("operation ipset.Destroy has not yet been implemented") + }), + IpsetGetHandler: ipset.GetHandlerFunc(func(params ipset.GetParams) middleware.Responder { + return middleware.NotImplemented("operation ipset.Get has not yet been implemented") + }), + IpsetGetAllHandler: ipset.GetAllHandlerFunc(func(params ipset.GetAllParams) middleware.Responder { + return middleware.NotImplemented("operation ipset.GetAll has not yet been implemented") + }), DeviceGetDeviceHandler: device.GetDeviceHandlerFunc(func(params device.GetDeviceParams) middleware.Responder { return middleware.NotImplemented("operation device.GetDevice has not yet been implemented") }), @@ -114,6 +133,9 @@ func NewDpvsAgentAPI(spec *loads.Document) *DpvsAgentAPI { VirtualserverGetVsVipPortRsHandler: virtualserver.GetVsVipPortRsHandlerFunc(func(params virtualserver.GetVsVipPortRsParams) middleware.Responder { return middleware.NotImplemented("operation virtualserver.GetVsVipPortRs has not yet been implemented") }), + IpsetIsInHandler: ipset.IsInHandlerFunc(func(params ipset.IsInParams) middleware.Responder { + return middleware.NotImplemented("operation ipset.IsIn has not yet been implemented") + }), VirtualserverPostVsVipPortAllowHandler: virtualserver.PostVsVipPortAllowHandlerFunc(func(params virtualserver.PostVsVipPortAllowParams) middleware.Responder { return middleware.NotImplemented("operation virtualserver.PostVsVipPortAllow has not yet been implemented") }), @@ -159,6 +181,9 @@ func NewDpvsAgentAPI(spec *loads.Document) *DpvsAgentAPI { VirtualserverPutVsVipPortRsHealthHandler: virtualserver.PutVsVipPortRsHealthHandlerFunc(func(params virtualserver.PutVsVipPortRsHealthParams) middleware.Responder { return middleware.NotImplemented("operation virtualserver.PutVsVipPortRsHealth has not yet been implemented") }), + IpsetReplaceMemberHandler: ipset.ReplaceMemberHandlerFunc(func(params ipset.ReplaceMemberParams) middleware.Responder { + return middleware.NotImplemented("operation ipset.ReplaceMember has not yet been implemented") + }), } } @@ -195,6 +220,12 @@ type DpvsAgentAPI struct { // - application/json JSONProducer runtime.Producer + // IpsetAddMemberHandler sets the operation handler for the add member operation + IpsetAddMemberHandler ipset.AddMemberHandler + // IpsetCreateHandler sets the operation handler for the create operation + IpsetCreateHandler ipset.CreateHandler + // IpsetDelMemberHandler sets the operation handler for the del member operation + IpsetDelMemberHandler ipset.DelMemberHandler // DeviceDeleteDeviceNameAddrHandler sets the operation handler for the delete device name addr operation DeviceDeleteDeviceNameAddrHandler device.DeleteDeviceNameAddrHandler // DeviceDeleteDeviceNameNetlinkHandler sets the operation handler for the delete device name netlink operation @@ -215,6 +246,12 @@ type DpvsAgentAPI struct { VirtualserverDeleteVsVipPortLaddrHandler virtualserver.DeleteVsVipPortLaddrHandler // VirtualserverDeleteVsVipPortRsHandler sets the operation handler for the delete vs vip port rs operation VirtualserverDeleteVsVipPortRsHandler virtualserver.DeleteVsVipPortRsHandler + // IpsetDestroyHandler sets the operation handler for the destroy operation + IpsetDestroyHandler ipset.DestroyHandler + // IpsetGetHandler sets the operation handler for the get operation + IpsetGetHandler ipset.GetHandler + // IpsetGetAllHandler sets the operation handler for the get all operation + IpsetGetAllHandler ipset.GetAllHandler // DeviceGetDeviceHandler sets the operation handler for the get device operation DeviceGetDeviceHandler device.GetDeviceHandler // DeviceGetDeviceNameAddrHandler sets the operation handler for the get device name addr operation @@ -241,6 +278,8 @@ type DpvsAgentAPI struct { VirtualserverGetVsVipPortLaddrHandler virtualserver.GetVsVipPortLaddrHandler // VirtualserverGetVsVipPortRsHandler sets the operation handler for the get vs vip port rs operation VirtualserverGetVsVipPortRsHandler virtualserver.GetVsVipPortRsHandler + // IpsetIsInHandler sets the operation handler for the is in operation + IpsetIsInHandler ipset.IsInHandler // VirtualserverPostVsVipPortAllowHandler sets the operation handler for the post vs vip port allow operation VirtualserverPostVsVipPortAllowHandler virtualserver.PostVsVipPortAllowHandler // VirtualserverPostVsVipPortDenyHandler sets the operation handler for the post vs vip port deny operation @@ -271,6 +310,8 @@ type DpvsAgentAPI struct { VirtualserverPutVsVipPortRsHandler virtualserver.PutVsVipPortRsHandler // VirtualserverPutVsVipPortRsHealthHandler sets the operation handler for the put vs vip port rs health operation VirtualserverPutVsVipPortRsHealthHandler virtualserver.PutVsVipPortRsHealthHandler + // IpsetReplaceMemberHandler sets the operation handler for the replace member operation + IpsetReplaceMemberHandler ipset.ReplaceMemberHandler // ServeError is called when an error is received, there is a default handler // but you can set your own with this @@ -348,6 +389,15 @@ func (o *DpvsAgentAPI) Validate() error { unregistered = append(unregistered, "JSONProducer") } + if o.IpsetAddMemberHandler == nil { + unregistered = append(unregistered, "ipset.AddMemberHandler") + } + if o.IpsetCreateHandler == nil { + unregistered = append(unregistered, "ipset.CreateHandler") + } + if o.IpsetDelMemberHandler == nil { + unregistered = append(unregistered, "ipset.DelMemberHandler") + } if o.DeviceDeleteDeviceNameAddrHandler == nil { unregistered = append(unregistered, "device.DeleteDeviceNameAddrHandler") } @@ -378,6 +428,15 @@ func (o *DpvsAgentAPI) Validate() error { if o.VirtualserverDeleteVsVipPortRsHandler == nil { unregistered = append(unregistered, "virtualserver.DeleteVsVipPortRsHandler") } + if o.IpsetDestroyHandler == nil { + unregistered = append(unregistered, "ipset.DestroyHandler") + } + if o.IpsetGetHandler == nil { + unregistered = append(unregistered, "ipset.GetHandler") + } + if o.IpsetGetAllHandler == nil { + unregistered = append(unregistered, "ipset.GetAllHandler") + } if o.DeviceGetDeviceHandler == nil { unregistered = append(unregistered, "device.GetDeviceHandler") } @@ -417,6 +476,9 @@ func (o *DpvsAgentAPI) Validate() error { if o.VirtualserverGetVsVipPortRsHandler == nil { unregistered = append(unregistered, "virtualserver.GetVsVipPortRsHandler") } + if o.IpsetIsInHandler == nil { + unregistered = append(unregistered, "ipset.IsInHandler") + } if o.VirtualserverPostVsVipPortAllowHandler == nil { unregistered = append(unregistered, "virtualserver.PostVsVipPortAllowHandler") } @@ -462,6 +524,9 @@ func (o *DpvsAgentAPI) Validate() error { if o.VirtualserverPutVsVipPortRsHealthHandler == nil { unregistered = append(unregistered, "virtualserver.PutVsVipPortRsHealthHandler") } + if o.IpsetReplaceMemberHandler == nil { + unregistered = append(unregistered, "ipset.ReplaceMemberHandler") + } if len(unregistered) > 0 { return fmt.Errorf("missing registration: %s", strings.Join(unregistered, ", ")) @@ -550,6 +615,18 @@ func (o *DpvsAgentAPI) initHandlerCache() { o.handlers = make(map[string]map[string]http.Handler) } + if o.handlers["POST"] == nil { + o.handlers["POST"] = make(map[string]http.Handler) + } + o.handlers["POST"]["/ipset/{name}/member"] = ipset.NewAddMember(o.context, o.IpsetAddMemberHandler) + if o.handlers["PUT"] == nil { + o.handlers["PUT"] = make(map[string]http.Handler) + } + o.handlers["PUT"]["/ipset/{name}"] = ipset.NewCreate(o.context, o.IpsetCreateHandler) + if o.handlers["DELETE"] == nil { + o.handlers["DELETE"] = make(map[string]http.Handler) + } + o.handlers["DELETE"]["/ipset/{name}/member"] = ipset.NewDelMember(o.context, o.IpsetDelMemberHandler) if o.handlers["DELETE"] == nil { o.handlers["DELETE"] = make(map[string]http.Handler) } @@ -590,6 +667,18 @@ func (o *DpvsAgentAPI) initHandlerCache() { o.handlers["DELETE"] = make(map[string]http.Handler) } o.handlers["DELETE"]["/vs/{VipPort}/rs"] = virtualserver.NewDeleteVsVipPortRs(o.context, o.VirtualserverDeleteVsVipPortRsHandler) + if o.handlers["DELETE"] == nil { + o.handlers["DELETE"] = make(map[string]http.Handler) + } + o.handlers["DELETE"]["/ipset/{name}"] = ipset.NewDestroy(o.context, o.IpsetDestroyHandler) + if o.handlers["GET"] == nil { + o.handlers["GET"] = make(map[string]http.Handler) + } + o.handlers["GET"]["/ipset/{name}"] = ipset.NewGet(o.context, o.IpsetGetHandler) + if o.handlers["GET"] == nil { + o.handlers["GET"] = make(map[string]http.Handler) + } + o.handlers["GET"]["/ipset"] = ipset.NewGetAll(o.context, o.IpsetGetAllHandler) if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } @@ -645,6 +734,10 @@ func (o *DpvsAgentAPI) initHandlerCache() { if o.handlers["POST"] == nil { o.handlers["POST"] = make(map[string]http.Handler) } + o.handlers["POST"]["/ipset/{name}/cell"] = ipset.NewIsIn(o.context, o.IpsetIsInHandler) + if o.handlers["POST"] == nil { + o.handlers["POST"] = make(map[string]http.Handler) + } o.handlers["POST"]["/vs/{VipPort}/allow"] = virtualserver.NewPostVsVipPortAllow(o.context, o.VirtualserverPostVsVipPortAllowHandler) if o.handlers["POST"] == nil { o.handlers["POST"] = make(map[string]http.Handler) @@ -702,6 +795,10 @@ func (o *DpvsAgentAPI) initHandlerCache() { o.handlers["PUT"] = make(map[string]http.Handler) } o.handlers["PUT"]["/vs/{VipPort}/rs/health"] = virtualserver.NewPutVsVipPortRsHealth(o.context, o.VirtualserverPutVsVipPortRsHealthHandler) + if o.handlers["PUT"] == nil { + o.handlers["PUT"] = make(map[string]http.Handler) + } + o.handlers["PUT"]["/ipset/{name}/member"] = ipset.NewReplaceMember(o.context, o.IpsetReplaceMemberHandler) } // Serve creates a http handler to serve the API over HTTP diff --git a/tools/dpvs-agent/restapi/operations/ipset/add_member.go b/tools/dpvs-agent/restapi/operations/ipset/add_member.go new file mode 100644 index 000000000..58948ac0f --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/add_member.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// AddMemberHandlerFunc turns a function with the right signature into a add member handler +type AddMemberHandlerFunc func(AddMemberParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn AddMemberHandlerFunc) Handle(params AddMemberParams) middleware.Responder { + return fn(params) +} + +// AddMemberHandler interface for that can handle valid add member params +type AddMemberHandler interface { + Handle(AddMemberParams) middleware.Responder +} + +// NewAddMember creates a new http.Handler for the add member operation +func NewAddMember(ctx *middleware.Context, handler AddMemberHandler) *AddMember { + return &AddMember{Context: ctx, Handler: handler} +} + +/* + AddMember swagger:route POST /ipset/{name}/member ipset addMember + +Add members to the ipset. +*/ +type AddMember struct { + Context *middleware.Context + Handler AddMemberHandler +} + +func (o *AddMember) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewAddMemberParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/add_member_parameters.go b/tools/dpvs-agent/restapi/operations/ipset/add_member_parameters.go new file mode 100644 index 000000000..b2b76bc29 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/add_member_parameters.go @@ -0,0 +1,101 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" + + "github.com/dpvs-agent/models" +) + +// NewAddMemberParams creates a new AddMemberParams object +// +// There are no default values defined in the spec. +func NewAddMemberParams() AddMemberParams { + + return AddMemberParams{} +} + +// AddMemberParams contains all the bound params for the add member operation +// typically these are obtained from a http.Request +// +// swagger:parameters AddMember +type AddMemberParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /* + In: body + */ + IpsetParam *models.IpsetInfo + /* + Required: true + In: path + */ + Name string +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewAddMemberParams() beforehand. +func (o *AddMemberParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + if runtime.HasBody(r) { + defer r.Body.Close() + var body models.IpsetInfo + if err := route.Consumer.Consume(r.Body, &body); err != nil { + res = append(res, errors.NewParseError("ipsetParam", "body", "", err)) + } else { + // validate body object + if err := body.Validate(route.Formats); err != nil { + res = append(res, err) + } + + ctx := validate.WithOperationRequest(r.Context()) + if err := body.ContextValidate(ctx, route.Formats); err != nil { + res = append(res, err) + } + + if len(res) == 0 { + o.IpsetParam = &body + } + } + } + + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindName binds and validates parameter Name from path. +func (o *AddMemberParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + // Parameter is provided by construction from the route + o.Name = raw + + return nil +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/add_member_responses.go b/tools/dpvs-agent/restapi/operations/ipset/add_member_responses.go new file mode 100644 index 000000000..89aba02da --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/add_member_responses.go @@ -0,0 +1,227 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" +) + +// AddMemberOKCode is the HTTP code returned for type AddMemberOK +const AddMemberOKCode int = 200 + +/* +AddMemberOK Existed + +swagger:response addMemberOK +*/ +type AddMemberOK struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewAddMemberOK creates AddMemberOK with default headers values +func NewAddMemberOK() *AddMemberOK { + + return &AddMemberOK{} +} + +// WithPayload adds the payload to the add member o k response +func (o *AddMemberOK) WithPayload(payload string) *AddMemberOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the add member o k response +func (o *AddMemberOK) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *AddMemberOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// AddMemberCreatedCode is the HTTP code returned for type AddMemberCreated +const AddMemberCreatedCode int = 201 + +/* +AddMemberCreated Created + +swagger:response addMemberCreated +*/ +type AddMemberCreated struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewAddMemberCreated creates AddMemberCreated with default headers values +func NewAddMemberCreated() *AddMemberCreated { + + return &AddMemberCreated{} +} + +// WithPayload adds the payload to the add member created response +func (o *AddMemberCreated) WithPayload(payload string) *AddMemberCreated { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the add member created response +func (o *AddMemberCreated) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *AddMemberCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(201) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// AddMemberBadRequestCode is the HTTP code returned for type AddMemberBadRequest +const AddMemberBadRequestCode int = 400 + +/* +AddMemberBadRequest Invalid ipset parameter + +swagger:response addMemberBadRequest +*/ +type AddMemberBadRequest struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewAddMemberBadRequest creates AddMemberBadRequest with default headers values +func NewAddMemberBadRequest() *AddMemberBadRequest { + + return &AddMemberBadRequest{} +} + +// WithPayload adds the payload to the add member bad request response +func (o *AddMemberBadRequest) WithPayload(payload string) *AddMemberBadRequest { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the add member bad request response +func (o *AddMemberBadRequest) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *AddMemberBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(400) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// AddMemberNotFoundCode is the HTTP code returned for type AddMemberNotFound +const AddMemberNotFoundCode int = 404 + +/* +AddMemberNotFound Ipset not found + +swagger:response addMemberNotFound +*/ +type AddMemberNotFound struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewAddMemberNotFound creates AddMemberNotFound with default headers values +func NewAddMemberNotFound() *AddMemberNotFound { + + return &AddMemberNotFound{} +} + +// WithPayload adds the payload to the add member not found response +func (o *AddMemberNotFound) WithPayload(payload string) *AddMemberNotFound { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the add member not found response +func (o *AddMemberNotFound) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *AddMemberNotFound) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(404) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// AddMemberFailureCode is the HTTP code returned for type AddMemberFailure +const AddMemberFailureCode int = 500 + +/* +AddMemberFailure Service not available + +swagger:response addMemberFailure +*/ +type AddMemberFailure struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewAddMemberFailure creates AddMemberFailure with default headers values +func NewAddMemberFailure() *AddMemberFailure { + + return &AddMemberFailure{} +} + +// WithPayload adds the payload to the add member failure response +func (o *AddMemberFailure) WithPayload(payload string) *AddMemberFailure { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the add member failure response +func (o *AddMemberFailure) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *AddMemberFailure) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(500) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/add_member_urlbuilder.go b/tools/dpvs-agent/restapi/operations/ipset/add_member_urlbuilder.go new file mode 100644 index 000000000..25bc040c4 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/add_member_urlbuilder.go @@ -0,0 +1,99 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" + "strings" +) + +// AddMemberURL generates an URL for the add member operation +type AddMemberURL struct { + Name string + + _basePath string + // avoid unkeyed usage + _ struct{} +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *AddMemberURL) WithBasePath(bp string) *AddMemberURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *AddMemberURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *AddMemberURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/ipset/{name}/member" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on AddMemberURL") + } + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/v2" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *AddMemberURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *AddMemberURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *AddMemberURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on AddMemberURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on AddMemberURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *AddMemberURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/create.go b/tools/dpvs-agent/restapi/operations/ipset/create.go new file mode 100644 index 000000000..211fa29e0 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/create.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// CreateHandlerFunc turns a function with the right signature into a create handler +type CreateHandlerFunc func(CreateParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn CreateHandlerFunc) Handle(params CreateParams) middleware.Responder { + return fn(params) +} + +// CreateHandler interface for that can handle valid create params +type CreateHandler interface { + Handle(CreateParams) middleware.Responder +} + +// NewCreate creates a new http.Handler for the create operation +func NewCreate(ctx *middleware.Context, handler CreateHandler) *Create { + return &Create{Context: ctx, Handler: handler} +} + +/* + Create swagger:route PUT /ipset/{name} ipset create + +Create an ipset named {name}. +*/ +type Create struct { + Context *middleware.Context + Handler CreateHandler +} + +func (o *Create) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewCreateParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/create_parameters.go b/tools/dpvs-agent/restapi/operations/ipset/create_parameters.go new file mode 100644 index 000000000..7aca005bf --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/create_parameters.go @@ -0,0 +1,101 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" + + "github.com/dpvs-agent/models" +) + +// NewCreateParams creates a new CreateParams object +// +// There are no default values defined in the spec. +func NewCreateParams() CreateParams { + + return CreateParams{} +} + +// CreateParams contains all the bound params for the create operation +// typically these are obtained from a http.Request +// +// swagger:parameters Create +type CreateParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /* + In: body + */ + IpsetParam *models.IpsetInfo + /* + Required: true + In: path + */ + Name string +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewCreateParams() beforehand. +func (o *CreateParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + if runtime.HasBody(r) { + defer r.Body.Close() + var body models.IpsetInfo + if err := route.Consumer.Consume(r.Body, &body); err != nil { + res = append(res, errors.NewParseError("ipsetParam", "body", "", err)) + } else { + // validate body object + if err := body.Validate(route.Formats); err != nil { + res = append(res, err) + } + + ctx := validate.WithOperationRequest(r.Context()) + if err := body.ContextValidate(ctx, route.Formats); err != nil { + res = append(res, err) + } + + if len(res) == 0 { + o.IpsetParam = &body + } + } + } + + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindName binds and validates parameter Name from path. +func (o *CreateParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + // Parameter is provided by construction from the route + o.Name = raw + + return nil +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/create_responses.go b/tools/dpvs-agent/restapi/operations/ipset/create_responses.go new file mode 100644 index 000000000..7bd038576 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/create_responses.go @@ -0,0 +1,227 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" +) + +// CreateOKCode is the HTTP code returned for type CreateOK +const CreateOKCode int = 200 + +/* +CreateOK Replaced + +swagger:response createOK +*/ +type CreateOK struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewCreateOK creates CreateOK with default headers values +func NewCreateOK() *CreateOK { + + return &CreateOK{} +} + +// WithPayload adds the payload to the create o k response +func (o *CreateOK) WithPayload(payload string) *CreateOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the create o k response +func (o *CreateOK) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *CreateOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// CreateCreatedCode is the HTTP code returned for type CreateCreated +const CreateCreatedCode int = 201 + +/* +CreateCreated Created + +swagger:response createCreated +*/ +type CreateCreated struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewCreateCreated creates CreateCreated with default headers values +func NewCreateCreated() *CreateCreated { + + return &CreateCreated{} +} + +// WithPayload adds the payload to the create created response +func (o *CreateCreated) WithPayload(payload string) *CreateCreated { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the create created response +func (o *CreateCreated) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *CreateCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(201) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// CreateBadRequestCode is the HTTP code returned for type CreateBadRequest +const CreateBadRequestCode int = 400 + +/* +CreateBadRequest Invalid ipset parameter + +swagger:response createBadRequest +*/ +type CreateBadRequest struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewCreateBadRequest creates CreateBadRequest with default headers values +func NewCreateBadRequest() *CreateBadRequest { + + return &CreateBadRequest{} +} + +// WithPayload adds the payload to the create bad request response +func (o *CreateBadRequest) WithPayload(payload string) *CreateBadRequest { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the create bad request response +func (o *CreateBadRequest) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *CreateBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(400) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// CreateNotFoundCode is the HTTP code returned for type CreateNotFound +const CreateNotFoundCode int = 404 + +/* +CreateNotFound Ipset not found + +swagger:response createNotFound +*/ +type CreateNotFound struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewCreateNotFound creates CreateNotFound with default headers values +func NewCreateNotFound() *CreateNotFound { + + return &CreateNotFound{} +} + +// WithPayload adds the payload to the create not found response +func (o *CreateNotFound) WithPayload(payload string) *CreateNotFound { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the create not found response +func (o *CreateNotFound) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *CreateNotFound) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(404) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// CreateFailureCode is the HTTP code returned for type CreateFailure +const CreateFailureCode int = 500 + +/* +CreateFailure Service not available + +swagger:response createFailure +*/ +type CreateFailure struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewCreateFailure creates CreateFailure with default headers values +func NewCreateFailure() *CreateFailure { + + return &CreateFailure{} +} + +// WithPayload adds the payload to the create failure response +func (o *CreateFailure) WithPayload(payload string) *CreateFailure { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the create failure response +func (o *CreateFailure) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *CreateFailure) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(500) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/create_urlbuilder.go b/tools/dpvs-agent/restapi/operations/ipset/create_urlbuilder.go new file mode 100644 index 000000000..fe549f1ab --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/create_urlbuilder.go @@ -0,0 +1,99 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" + "strings" +) + +// CreateURL generates an URL for the create operation +type CreateURL struct { + Name string + + _basePath string + // avoid unkeyed usage + _ struct{} +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *CreateURL) WithBasePath(bp string) *CreateURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *CreateURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *CreateURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/ipset/{name}" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on CreateURL") + } + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/v2" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *CreateURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *CreateURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *CreateURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on CreateURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on CreateURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *CreateURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/del_member.go b/tools/dpvs-agent/restapi/operations/ipset/del_member.go new file mode 100644 index 000000000..c72e13706 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/del_member.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// DelMemberHandlerFunc turns a function with the right signature into a del member handler +type DelMemberHandlerFunc func(DelMemberParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn DelMemberHandlerFunc) Handle(params DelMemberParams) middleware.Responder { + return fn(params) +} + +// DelMemberHandler interface for that can handle valid del member params +type DelMemberHandler interface { + Handle(DelMemberParams) middleware.Responder +} + +// NewDelMember creates a new http.Handler for the del member operation +func NewDelMember(ctx *middleware.Context, handler DelMemberHandler) *DelMember { + return &DelMember{Context: ctx, Handler: handler} +} + +/* + DelMember swagger:route DELETE /ipset/{name}/member ipset delMember + +Delete members from the ipset. +*/ +type DelMember struct { + Context *middleware.Context + Handler DelMemberHandler +} + +func (o *DelMember) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewDelMemberParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/del_member_parameters.go b/tools/dpvs-agent/restapi/operations/ipset/del_member_parameters.go new file mode 100644 index 000000000..58ca3b276 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/del_member_parameters.go @@ -0,0 +1,101 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" + + "github.com/dpvs-agent/models" +) + +// NewDelMemberParams creates a new DelMemberParams object +// +// There are no default values defined in the spec. +func NewDelMemberParams() DelMemberParams { + + return DelMemberParams{} +} + +// DelMemberParams contains all the bound params for the del member operation +// typically these are obtained from a http.Request +// +// swagger:parameters DelMember +type DelMemberParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /* + In: body + */ + IpsetParam *models.IpsetInfo + /* + Required: true + In: path + */ + Name string +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewDelMemberParams() beforehand. +func (o *DelMemberParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + if runtime.HasBody(r) { + defer r.Body.Close() + var body models.IpsetInfo + if err := route.Consumer.Consume(r.Body, &body); err != nil { + res = append(res, errors.NewParseError("ipsetParam", "body", "", err)) + } else { + // validate body object + if err := body.Validate(route.Formats); err != nil { + res = append(res, err) + } + + ctx := validate.WithOperationRequest(r.Context()) + if err := body.ContextValidate(ctx, route.Formats); err != nil { + res = append(res, err) + } + + if len(res) == 0 { + o.IpsetParam = &body + } + } + } + + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindName binds and validates parameter Name from path. +func (o *DelMemberParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + // Parameter is provided by construction from the route + o.Name = raw + + return nil +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/del_member_responses.go b/tools/dpvs-agent/restapi/operations/ipset/del_member_responses.go new file mode 100644 index 000000000..34767169d --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/del_member_responses.go @@ -0,0 +1,184 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" +) + +// DelMemberOKCode is the HTTP code returned for type DelMemberOK +const DelMemberOKCode int = 200 + +/* +DelMemberOK Succeed + +swagger:response delMemberOK +*/ +type DelMemberOK struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewDelMemberOK creates DelMemberOK with default headers values +func NewDelMemberOK() *DelMemberOK { + + return &DelMemberOK{} +} + +// WithPayload adds the payload to the del member o k response +func (o *DelMemberOK) WithPayload(payload string) *DelMemberOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the del member o k response +func (o *DelMemberOK) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DelMemberOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// DelMemberBadRequestCode is the HTTP code returned for type DelMemberBadRequest +const DelMemberBadRequestCode int = 400 + +/* +DelMemberBadRequest Invalid ipset parameter + +swagger:response delMemberBadRequest +*/ +type DelMemberBadRequest struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewDelMemberBadRequest creates DelMemberBadRequest with default headers values +func NewDelMemberBadRequest() *DelMemberBadRequest { + + return &DelMemberBadRequest{} +} + +// WithPayload adds the payload to the del member bad request response +func (o *DelMemberBadRequest) WithPayload(payload string) *DelMemberBadRequest { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the del member bad request response +func (o *DelMemberBadRequest) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DelMemberBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(400) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// DelMemberNotFoundCode is the HTTP code returned for type DelMemberNotFound +const DelMemberNotFoundCode int = 404 + +/* +DelMemberNotFound Ipset not found + +swagger:response delMemberNotFound +*/ +type DelMemberNotFound struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewDelMemberNotFound creates DelMemberNotFound with default headers values +func NewDelMemberNotFound() *DelMemberNotFound { + + return &DelMemberNotFound{} +} + +// WithPayload adds the payload to the del member not found response +func (o *DelMemberNotFound) WithPayload(payload string) *DelMemberNotFound { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the del member not found response +func (o *DelMemberNotFound) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DelMemberNotFound) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(404) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// DelMemberFailureCode is the HTTP code returned for type DelMemberFailure +const DelMemberFailureCode int = 500 + +/* +DelMemberFailure Service not available + +swagger:response delMemberFailure +*/ +type DelMemberFailure struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewDelMemberFailure creates DelMemberFailure with default headers values +func NewDelMemberFailure() *DelMemberFailure { + + return &DelMemberFailure{} +} + +// WithPayload adds the payload to the del member failure response +func (o *DelMemberFailure) WithPayload(payload string) *DelMemberFailure { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the del member failure response +func (o *DelMemberFailure) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DelMemberFailure) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(500) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/del_member_urlbuilder.go b/tools/dpvs-agent/restapi/operations/ipset/del_member_urlbuilder.go new file mode 100644 index 000000000..8da232e0b --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/del_member_urlbuilder.go @@ -0,0 +1,99 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" + "strings" +) + +// DelMemberURL generates an URL for the del member operation +type DelMemberURL struct { + Name string + + _basePath string + // avoid unkeyed usage + _ struct{} +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *DelMemberURL) WithBasePath(bp string) *DelMemberURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *DelMemberURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *DelMemberURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/ipset/{name}/member" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on DelMemberURL") + } + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/v2" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *DelMemberURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *DelMemberURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *DelMemberURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on DelMemberURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on DelMemberURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *DelMemberURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/destroy.go b/tools/dpvs-agent/restapi/operations/ipset/destroy.go new file mode 100644 index 000000000..6f8c38afd --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/destroy.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// DestroyHandlerFunc turns a function with the right signature into a destroy handler +type DestroyHandlerFunc func(DestroyParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn DestroyHandlerFunc) Handle(params DestroyParams) middleware.Responder { + return fn(params) +} + +// DestroyHandler interface for that can handle valid destroy params +type DestroyHandler interface { + Handle(DestroyParams) middleware.Responder +} + +// NewDestroy creates a new http.Handler for the destroy operation +func NewDestroy(ctx *middleware.Context, handler DestroyHandler) *Destroy { + return &Destroy{Context: ctx, Handler: handler} +} + +/* + Destroy swagger:route DELETE /ipset/{name} ipset destroy + +Delete the ipset named {name}. +*/ +type Destroy struct { + Context *middleware.Context + Handler DestroyHandler +} + +func (o *Destroy) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewDestroyParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/destroy_parameters.go b/tools/dpvs-agent/restapi/operations/ipset/destroy_parameters.go new file mode 100644 index 000000000..738d1688f --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/destroy_parameters.go @@ -0,0 +1,71 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" +) + +// NewDestroyParams creates a new DestroyParams object +// +// There are no default values defined in the spec. +func NewDestroyParams() DestroyParams { + + return DestroyParams{} +} + +// DestroyParams contains all the bound params for the destroy operation +// typically these are obtained from a http.Request +// +// swagger:parameters Destroy +type DestroyParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /* + Required: true + In: path + */ + Name string +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewDestroyParams() beforehand. +func (o *DestroyParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindName binds and validates parameter Name from path. +func (o *DestroyParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + // Parameter is provided by construction from the route + o.Name = raw + + return nil +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/destroy_responses.go b/tools/dpvs-agent/restapi/operations/ipset/destroy_responses.go new file mode 100644 index 000000000..4499b32c6 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/destroy_responses.go @@ -0,0 +1,141 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" +) + +// DestroyOKCode is the HTTP code returned for type DestroyOK +const DestroyOKCode int = 200 + +/* +DestroyOK Deleted + +swagger:response destroyOK +*/ +type DestroyOK struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewDestroyOK creates DestroyOK with default headers values +func NewDestroyOK() *DestroyOK { + + return &DestroyOK{} +} + +// WithPayload adds the payload to the destroy o k response +func (o *DestroyOK) WithPayload(payload string) *DestroyOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the destroy o k response +func (o *DestroyOK) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DestroyOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// DestroyNotFoundCode is the HTTP code returned for type DestroyNotFound +const DestroyNotFoundCode int = 404 + +/* +DestroyNotFound Ipset not found + +swagger:response destroyNotFound +*/ +type DestroyNotFound struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewDestroyNotFound creates DestroyNotFound with default headers values +func NewDestroyNotFound() *DestroyNotFound { + + return &DestroyNotFound{} +} + +// WithPayload adds the payload to the destroy not found response +func (o *DestroyNotFound) WithPayload(payload string) *DestroyNotFound { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the destroy not found response +func (o *DestroyNotFound) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DestroyNotFound) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(404) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// DestroyFailureCode is the HTTP code returned for type DestroyFailure +const DestroyFailureCode int = 500 + +/* +DestroyFailure Service not available + +swagger:response destroyFailure +*/ +type DestroyFailure struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewDestroyFailure creates DestroyFailure with default headers values +func NewDestroyFailure() *DestroyFailure { + + return &DestroyFailure{} +} + +// WithPayload adds the payload to the destroy failure response +func (o *DestroyFailure) WithPayload(payload string) *DestroyFailure { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the destroy failure response +func (o *DestroyFailure) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DestroyFailure) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(500) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/destroy_urlbuilder.go b/tools/dpvs-agent/restapi/operations/ipset/destroy_urlbuilder.go new file mode 100644 index 000000000..fd259b65f --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/destroy_urlbuilder.go @@ -0,0 +1,99 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" + "strings" +) + +// DestroyURL generates an URL for the destroy operation +type DestroyURL struct { + Name string + + _basePath string + // avoid unkeyed usage + _ struct{} +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *DestroyURL) WithBasePath(bp string) *DestroyURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *DestroyURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *DestroyURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/ipset/{name}" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on DestroyURL") + } + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/v2" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *DestroyURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *DestroyURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *DestroyURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on DestroyURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on DestroyURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *DestroyURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/get.go b/tools/dpvs-agent/restapi/operations/ipset/get.go new file mode 100644 index 000000000..35d31e50e --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/get.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// GetHandlerFunc turns a function with the right signature into a get handler +type GetHandlerFunc func(GetParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn GetHandlerFunc) Handle(params GetParams) middleware.Responder { + return fn(params) +} + +// GetHandler interface for that can handle valid get params +type GetHandler interface { + Handle(GetParams) middleware.Responder +} + +// NewGet creates a new http.Handler for the get operation +func NewGet(ctx *middleware.Context, handler GetHandler) *Get { + return &Get{Context: ctx, Handler: handler} +} + +/* + Get swagger:route GET /ipset/{name} ipset get + +Get a specific ipset and its members. +*/ +type Get struct { + Context *middleware.Context + Handler GetHandler +} + +func (o *Get) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewGetParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/get_all.go b/tools/dpvs-agent/restapi/operations/ipset/get_all.go new file mode 100644 index 000000000..d5a981a4a --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/get_all.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// GetAllHandlerFunc turns a function with the right signature into a get all handler +type GetAllHandlerFunc func(GetAllParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn GetAllHandlerFunc) Handle(params GetAllParams) middleware.Responder { + return fn(params) +} + +// GetAllHandler interface for that can handle valid get all params +type GetAllHandler interface { + Handle(GetAllParams) middleware.Responder +} + +// NewGetAll creates a new http.Handler for the get all operation +func NewGetAll(ctx *middleware.Context, handler GetAllHandler) *GetAll { + return &GetAll{Context: ctx, Handler: handler} +} + +/* + GetAll swagger:route GET /ipset ipset getAll + +Get all the ipsets and members. +*/ +type GetAll struct { + Context *middleware.Context + Handler GetAllHandler +} + +func (o *GetAll) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewGetAllParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/get_all_parameters.go b/tools/dpvs-agent/restapi/operations/ipset/get_all_parameters.go new file mode 100644 index 000000000..a92ff5454 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/get_all_parameters.go @@ -0,0 +1,46 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime/middleware" +) + +// NewGetAllParams creates a new GetAllParams object +// +// There are no default values defined in the spec. +func NewGetAllParams() GetAllParams { + + return GetAllParams{} +} + +// GetAllParams contains all the bound params for the get all operation +// typically these are obtained from a http.Request +// +// swagger:parameters GetAll +type GetAllParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewGetAllParams() beforehand. +func (o *GetAllParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/get_all_responses.go b/tools/dpvs-agent/restapi/operations/ipset/get_all_responses.go new file mode 100644 index 000000000..433af030f --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/get_all_responses.go @@ -0,0 +1,102 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" + + "github.com/dpvs-agent/models" +) + +// GetAllOKCode is the HTTP code returned for type GetAllOK +const GetAllOKCode int = 200 + +/* +GetAllOK Success + +swagger:response getAllOK +*/ +type GetAllOK struct { + + /* + In: Body + */ + Payload *models.IpsetInfoArray `json:"body,omitempty"` +} + +// NewGetAllOK creates GetAllOK with default headers values +func NewGetAllOK() *GetAllOK { + + return &GetAllOK{} +} + +// WithPayload adds the payload to the get all o k response +func (o *GetAllOK) WithPayload(payload *models.IpsetInfoArray) *GetAllOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get all o k response +func (o *GetAllOK) SetPayload(payload *models.IpsetInfoArray) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetAllOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// GetAllFailureCode is the HTTP code returned for type GetAllFailure +const GetAllFailureCode int = 500 + +/* +GetAllFailure Service not available + +swagger:response getAllFailure +*/ +type GetAllFailure struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewGetAllFailure creates GetAllFailure with default headers values +func NewGetAllFailure() *GetAllFailure { + + return &GetAllFailure{} +} + +// WithPayload adds the payload to the get all failure response +func (o *GetAllFailure) WithPayload(payload string) *GetAllFailure { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get all failure response +func (o *GetAllFailure) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetAllFailure) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(500) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/get_all_urlbuilder.go b/tools/dpvs-agent/restapi/operations/ipset/get_all_urlbuilder.go new file mode 100644 index 000000000..2fd0ac230 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/get_all_urlbuilder.go @@ -0,0 +1,87 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" +) + +// GetAllURL generates an URL for the get all operation +type GetAllURL struct { + _basePath string +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetAllURL) WithBasePath(bp string) *GetAllURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetAllURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *GetAllURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/ipset" + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/v2" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *GetAllURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *GetAllURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *GetAllURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on GetAllURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on GetAllURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *GetAllURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/get_parameters.go b/tools/dpvs-agent/restapi/operations/ipset/get_parameters.go new file mode 100644 index 000000000..10a335867 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/get_parameters.go @@ -0,0 +1,71 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" +) + +// NewGetParams creates a new GetParams object +// +// There are no default values defined in the spec. +func NewGetParams() GetParams { + + return GetParams{} +} + +// GetParams contains all the bound params for the get operation +// typically these are obtained from a http.Request +// +// swagger:parameters Get +type GetParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /* + Required: true + In: path + */ + Name string +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewGetParams() beforehand. +func (o *GetParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindName binds and validates parameter Name from path. +func (o *GetParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + // Parameter is provided by construction from the route + o.Name = raw + + return nil +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/get_responses.go b/tools/dpvs-agent/restapi/operations/ipset/get_responses.go new file mode 100644 index 000000000..c2018050a --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/get_responses.go @@ -0,0 +1,145 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" + + "github.com/dpvs-agent/models" +) + +// GetOKCode is the HTTP code returned for type GetOK +const GetOKCode int = 200 + +/* +GetOK Success + +swagger:response getOK +*/ +type GetOK struct { + + /* + In: Body + */ + Payload *models.IpsetInfo `json:"body,omitempty"` +} + +// NewGetOK creates GetOK with default headers values +func NewGetOK() *GetOK { + + return &GetOK{} +} + +// WithPayload adds the payload to the get o k response +func (o *GetOK) WithPayload(payload *models.IpsetInfo) *GetOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get o k response +func (o *GetOK) SetPayload(payload *models.IpsetInfo) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// GetNotFoundCode is the HTTP code returned for type GetNotFound +const GetNotFoundCode int = 404 + +/* +GetNotFound Ipset not found + +swagger:response getNotFound +*/ +type GetNotFound struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewGetNotFound creates GetNotFound with default headers values +func NewGetNotFound() *GetNotFound { + + return &GetNotFound{} +} + +// WithPayload adds the payload to the get not found response +func (o *GetNotFound) WithPayload(payload string) *GetNotFound { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get not found response +func (o *GetNotFound) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetNotFound) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(404) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// GetFailureCode is the HTTP code returned for type GetFailure +const GetFailureCode int = 500 + +/* +GetFailure Service not available + +swagger:response getFailure +*/ +type GetFailure struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewGetFailure creates GetFailure with default headers values +func NewGetFailure() *GetFailure { + + return &GetFailure{} +} + +// WithPayload adds the payload to the get failure response +func (o *GetFailure) WithPayload(payload string) *GetFailure { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get failure response +func (o *GetFailure) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetFailure) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(500) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/get_urlbuilder.go b/tools/dpvs-agent/restapi/operations/ipset/get_urlbuilder.go new file mode 100644 index 000000000..0eeff8b86 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/get_urlbuilder.go @@ -0,0 +1,99 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" + "strings" +) + +// GetURL generates an URL for the get operation +type GetURL struct { + Name string + + _basePath string + // avoid unkeyed usage + _ struct{} +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetURL) WithBasePath(bp string) *GetURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *GetURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/ipset/{name}" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on GetURL") + } + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/v2" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *GetURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *GetURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *GetURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on GetURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on GetURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *GetURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/is_in.go b/tools/dpvs-agent/restapi/operations/ipset/is_in.go new file mode 100644 index 000000000..ef011b31a --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/is_in.go @@ -0,0 +1,120 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "context" + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// IsInHandlerFunc turns a function with the right signature into a is in handler +type IsInHandlerFunc func(IsInParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn IsInHandlerFunc) Handle(params IsInParams) middleware.Responder { + return fn(params) +} + +// IsInHandler interface for that can handle valid is in params +type IsInHandler interface { + Handle(IsInParams) middleware.Responder +} + +// NewIsIn creates a new http.Handler for the is in operation +func NewIsIn(ctx *middleware.Context, handler IsInHandler) *IsIn { + return &IsIn{Context: ctx, Handler: handler} +} + +/* + IsIn swagger:route POST /ipset/{name}/cell ipset isIn + +Check if an object in the ipset. +*/ +type IsIn struct { + Context *middleware.Context + Handler IsInHandler +} + +func (o *IsIn) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewIsInParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} + +// IsInOKBody is in o k body +// +// swagger:model IsInOKBody +type IsInOKBody struct { + + // message + Message string `json:"Message,omitempty"` + + // result + // Required: true + Result *bool `json:"Result"` +} + +// Validate validates this is in o k body +func (o *IsInOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateResult(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *IsInOKBody) validateResult(formats strfmt.Registry) error { + + if err := validate.Required("isInOK"+"."+"Result", "body", o.Result); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this is in o k body based on context it is used +func (o *IsInOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *IsInOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *IsInOKBody) UnmarshalBinary(b []byte) error { + var res IsInOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/is_in_parameters.go b/tools/dpvs-agent/restapi/operations/ipset/is_in_parameters.go new file mode 100644 index 000000000..06236abce --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/is_in_parameters.go @@ -0,0 +1,101 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" + + "github.com/dpvs-agent/models" +) + +// NewIsInParams creates a new IsInParams object +// +// There are no default values defined in the spec. +func NewIsInParams() IsInParams { + + return IsInParams{} +} + +// IsInParams contains all the bound params for the is in operation +// typically these are obtained from a http.Request +// +// swagger:parameters IsIn +type IsInParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /* + In: body + */ + IpsetCell *models.IpsetCell + /* + Required: true + In: path + */ + Name string +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewIsInParams() beforehand. +func (o *IsInParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + if runtime.HasBody(r) { + defer r.Body.Close() + var body models.IpsetCell + if err := route.Consumer.Consume(r.Body, &body); err != nil { + res = append(res, errors.NewParseError("ipsetCell", "body", "", err)) + } else { + // validate body object + if err := body.Validate(route.Formats); err != nil { + res = append(res, err) + } + + ctx := validate.WithOperationRequest(r.Context()) + if err := body.ContextValidate(ctx, route.Formats); err != nil { + res = append(res, err) + } + + if len(res) == 0 { + o.IpsetCell = &body + } + } + } + + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindName binds and validates parameter Name from path. +func (o *IsInParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + // Parameter is provided by construction from the route + o.Name = raw + + return nil +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/is_in_responses.go b/tools/dpvs-agent/restapi/operations/ipset/is_in_responses.go new file mode 100644 index 000000000..4565ceabb --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/is_in_responses.go @@ -0,0 +1,186 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" +) + +// IsInOKCode is the HTTP code returned for type IsInOK +const IsInOKCode int = 200 + +/* +IsInOK Succeed + +swagger:response isInOK +*/ +type IsInOK struct { + + /* + In: Body + */ + Payload *IsInOKBody `json:"body,omitempty"` +} + +// NewIsInOK creates IsInOK with default headers values +func NewIsInOK() *IsInOK { + + return &IsInOK{} +} + +// WithPayload adds the payload to the is in o k response +func (o *IsInOK) WithPayload(payload *IsInOKBody) *IsInOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the is in o k response +func (o *IsInOK) SetPayload(payload *IsInOKBody) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *IsInOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// IsInBadRequestCode is the HTTP code returned for type IsInBadRequest +const IsInBadRequestCode int = 400 + +/* +IsInBadRequest Invalid ipset parameter + +swagger:response isInBadRequest +*/ +type IsInBadRequest struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewIsInBadRequest creates IsInBadRequest with default headers values +func NewIsInBadRequest() *IsInBadRequest { + + return &IsInBadRequest{} +} + +// WithPayload adds the payload to the is in bad request response +func (o *IsInBadRequest) WithPayload(payload string) *IsInBadRequest { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the is in bad request response +func (o *IsInBadRequest) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *IsInBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(400) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// IsInNotFoundCode is the HTTP code returned for type IsInNotFound +const IsInNotFoundCode int = 404 + +/* +IsInNotFound Ipset not found + +swagger:response isInNotFound +*/ +type IsInNotFound struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewIsInNotFound creates IsInNotFound with default headers values +func NewIsInNotFound() *IsInNotFound { + + return &IsInNotFound{} +} + +// WithPayload adds the payload to the is in not found response +func (o *IsInNotFound) WithPayload(payload string) *IsInNotFound { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the is in not found response +func (o *IsInNotFound) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *IsInNotFound) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(404) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// IsInFailureCode is the HTTP code returned for type IsInFailure +const IsInFailureCode int = 500 + +/* +IsInFailure Service not available + +swagger:response isInFailure +*/ +type IsInFailure struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewIsInFailure creates IsInFailure with default headers values +func NewIsInFailure() *IsInFailure { + + return &IsInFailure{} +} + +// WithPayload adds the payload to the is in failure response +func (o *IsInFailure) WithPayload(payload string) *IsInFailure { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the is in failure response +func (o *IsInFailure) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *IsInFailure) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(500) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/is_in_urlbuilder.go b/tools/dpvs-agent/restapi/operations/ipset/is_in_urlbuilder.go new file mode 100644 index 000000000..4565d4dda --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/is_in_urlbuilder.go @@ -0,0 +1,99 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" + "strings" +) + +// IsInURL generates an URL for the is in operation +type IsInURL struct { + Name string + + _basePath string + // avoid unkeyed usage + _ struct{} +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *IsInURL) WithBasePath(bp string) *IsInURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *IsInURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *IsInURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/ipset/{name}/cell" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on IsInURL") + } + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/v2" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *IsInURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *IsInURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *IsInURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on IsInURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on IsInURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *IsInURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/replace_member.go b/tools/dpvs-agent/restapi/operations/ipset/replace_member.go new file mode 100644 index 000000000..09668e599 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/replace_member.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// ReplaceMemberHandlerFunc turns a function with the right signature into a replace member handler +type ReplaceMemberHandlerFunc func(ReplaceMemberParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn ReplaceMemberHandlerFunc) Handle(params ReplaceMemberParams) middleware.Responder { + return fn(params) +} + +// ReplaceMemberHandler interface for that can handle valid replace member params +type ReplaceMemberHandler interface { + Handle(ReplaceMemberParams) middleware.Responder +} + +// NewReplaceMember creates a new http.Handler for the replace member operation +func NewReplaceMember(ctx *middleware.Context, handler ReplaceMemberHandler) *ReplaceMember { + return &ReplaceMember{Context: ctx, Handler: handler} +} + +/* + ReplaceMember swagger:route PUT /ipset/{name}/member ipset replaceMember + +Reset the whole ipset members. +*/ +type ReplaceMember struct { + Context *middleware.Context + Handler ReplaceMemberHandler +} + +func (o *ReplaceMember) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewReplaceMemberParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/replace_member_parameters.go b/tools/dpvs-agent/restapi/operations/ipset/replace_member_parameters.go new file mode 100644 index 000000000..95c1cb0da --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/replace_member_parameters.go @@ -0,0 +1,101 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" + + "github.com/dpvs-agent/models" +) + +// NewReplaceMemberParams creates a new ReplaceMemberParams object +// +// There are no default values defined in the spec. +func NewReplaceMemberParams() ReplaceMemberParams { + + return ReplaceMemberParams{} +} + +// ReplaceMemberParams contains all the bound params for the replace member operation +// typically these are obtained from a http.Request +// +// swagger:parameters ReplaceMember +type ReplaceMemberParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /* + In: body + */ + IpsetParam *models.IpsetInfo + /* + Required: true + In: path + */ + Name string +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewReplaceMemberParams() beforehand. +func (o *ReplaceMemberParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + if runtime.HasBody(r) { + defer r.Body.Close() + var body models.IpsetInfo + if err := route.Consumer.Consume(r.Body, &body); err != nil { + res = append(res, errors.NewParseError("ipsetParam", "body", "", err)) + } else { + // validate body object + if err := body.Validate(route.Formats); err != nil { + res = append(res, err) + } + + ctx := validate.WithOperationRequest(r.Context()) + if err := body.ContextValidate(ctx, route.Formats); err != nil { + res = append(res, err) + } + + if len(res) == 0 { + o.IpsetParam = &body + } + } + } + + rName, rhkName, _ := route.Params.GetOK("name") + if err := o.bindName(rName, rhkName, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindName binds and validates parameter Name from path. +func (o *ReplaceMemberParams) bindName(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + // Parameter is provided by construction from the route + o.Name = raw + + return nil +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/replace_member_responses.go b/tools/dpvs-agent/restapi/operations/ipset/replace_member_responses.go new file mode 100644 index 000000000..f402f2f43 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/replace_member_responses.go @@ -0,0 +1,184 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" +) + +// ReplaceMemberOKCode is the HTTP code returned for type ReplaceMemberOK +const ReplaceMemberOKCode int = 200 + +/* +ReplaceMemberOK Succeed + +swagger:response replaceMemberOK +*/ +type ReplaceMemberOK struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewReplaceMemberOK creates ReplaceMemberOK with default headers values +func NewReplaceMemberOK() *ReplaceMemberOK { + + return &ReplaceMemberOK{} +} + +// WithPayload adds the payload to the replace member o k response +func (o *ReplaceMemberOK) WithPayload(payload string) *ReplaceMemberOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the replace member o k response +func (o *ReplaceMemberOK) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *ReplaceMemberOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// ReplaceMemberBadRequestCode is the HTTP code returned for type ReplaceMemberBadRequest +const ReplaceMemberBadRequestCode int = 400 + +/* +ReplaceMemberBadRequest Invalid ipset parameter + +swagger:response replaceMemberBadRequest +*/ +type ReplaceMemberBadRequest struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewReplaceMemberBadRequest creates ReplaceMemberBadRequest with default headers values +func NewReplaceMemberBadRequest() *ReplaceMemberBadRequest { + + return &ReplaceMemberBadRequest{} +} + +// WithPayload adds the payload to the replace member bad request response +func (o *ReplaceMemberBadRequest) WithPayload(payload string) *ReplaceMemberBadRequest { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the replace member bad request response +func (o *ReplaceMemberBadRequest) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *ReplaceMemberBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(400) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// ReplaceMemberNotFoundCode is the HTTP code returned for type ReplaceMemberNotFound +const ReplaceMemberNotFoundCode int = 404 + +/* +ReplaceMemberNotFound Ipset not found + +swagger:response replaceMemberNotFound +*/ +type ReplaceMemberNotFound struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewReplaceMemberNotFound creates ReplaceMemberNotFound with default headers values +func NewReplaceMemberNotFound() *ReplaceMemberNotFound { + + return &ReplaceMemberNotFound{} +} + +// WithPayload adds the payload to the replace member not found response +func (o *ReplaceMemberNotFound) WithPayload(payload string) *ReplaceMemberNotFound { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the replace member not found response +func (o *ReplaceMemberNotFound) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *ReplaceMemberNotFound) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(404) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} + +// ReplaceMemberFailureCode is the HTTP code returned for type ReplaceMemberFailure +const ReplaceMemberFailureCode int = 500 + +/* +ReplaceMemberFailure Service not available + +swagger:response replaceMemberFailure +*/ +type ReplaceMemberFailure struct { + + /* + In: Body + */ + Payload string `json:"body,omitempty"` +} + +// NewReplaceMemberFailure creates ReplaceMemberFailure with default headers values +func NewReplaceMemberFailure() *ReplaceMemberFailure { + + return &ReplaceMemberFailure{} +} + +// WithPayload adds the payload to the replace member failure response +func (o *ReplaceMemberFailure) WithPayload(payload string) *ReplaceMemberFailure { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the replace member failure response +func (o *ReplaceMemberFailure) SetPayload(payload string) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *ReplaceMemberFailure) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(500) + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } +} diff --git a/tools/dpvs-agent/restapi/operations/ipset/replace_member_urlbuilder.go b/tools/dpvs-agent/restapi/operations/ipset/replace_member_urlbuilder.go new file mode 100644 index 000000000..e49b05b76 --- /dev/null +++ b/tools/dpvs-agent/restapi/operations/ipset/replace_member_urlbuilder.go @@ -0,0 +1,99 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package ipset + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" + "strings" +) + +// ReplaceMemberURL generates an URL for the replace member operation +type ReplaceMemberURL struct { + Name string + + _basePath string + // avoid unkeyed usage + _ struct{} +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *ReplaceMemberURL) WithBasePath(bp string) *ReplaceMemberURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *ReplaceMemberURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *ReplaceMemberURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/ipset/{name}/member" + + name := o.Name + if name != "" { + _path = strings.Replace(_path, "{name}", name, -1) + } else { + return nil, errors.New("name is required on ReplaceMemberURL") + } + + _basePath := o._basePath + if _basePath == "" { + _basePath = "/v2" + } + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *ReplaceMemberURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *ReplaceMemberURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *ReplaceMemberURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on ReplaceMemberURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on ReplaceMemberURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *ReplaceMemberURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/tools/ipvsadm/ipvsadm.c b/tools/ipvsadm/ipvsadm.c index 6e8923d49..4938cedd0 100644 --- a/tools/ipvsadm/ipvsadm.c +++ b/tools/ipvsadm/ipvsadm.c @@ -902,29 +902,37 @@ parse_options(int argc, char **argv, struct ipvs_command_entry *ce, { dpvs_service_compat_t dpvs_svc; set_option(options,OPT_BLKLST_ADDRESS); - parse = parse_service(optarg, - &dpvs_svc); - if (!(parse & SERVICE_ADDR)) - fail(2, "illegal blacklist address"); - - ce->dpvs_blklst.af = dpvs_svc.af; - ce->dpvs_blklst.blklst = dpvs_svc.addr; + if (!strncmp(optarg, "ipset:", strlen("ipset:"))) { + strncpy(ce->dpvs_blklst.ipset, &optarg[strlen("ipset:")], + sizeof(ce->dpvs_blklst.ipset) - 1); + } else { + parse = parse_service(optarg, &dpvs_svc); + if (parse & SERVICE_ADDR) { + ce->dpvs_blklst.af = dpvs_svc.af; + ce->dpvs_blklst.subject = dpvs_svc.addr; + } else { + fail(2, "illegal blacklist entry format, require [ IP | ipset:NAME ]"); + } + } break; - } case '2': { dpvs_service_compat_t dpvs_svc; set_option(options,OPT_WHTLST_ADDRESS); - parse = parse_service(optarg, - &dpvs_svc); - if (!(parse & SERVICE_ADDR)) - fail(2, "illegal whitelist address"); - - ce->dpvs_whtlst.af = dpvs_svc.af; - ce->dpvs_whtlst.whtlst = dpvs_svc.addr; + if (!strncmp(optarg, "ipset:", strlen("ipset:"))) { + strncpy(ce->dpvs_whtlst.ipset, &optarg[strlen("ipset:")], + sizeof(ce->dpvs_whtlst.ipset) - 1); + } else { + parse = parse_service(optarg, &dpvs_svc); + if (parse & SERVICE_ADDR) { + ce->dpvs_whtlst.af = dpvs_svc.af; + ce->dpvs_whtlst.subject = dpvs_svc.addr; + } else { + fail(2, "illegal whitelist entry format, require [ IP | ipset:NAME ]"); + } + } break; - } case 'F': set_option(options, OPT_IFNAME); @@ -1682,12 +1690,12 @@ static void usage_exit(const char *program, const int exit_status) " --add-laddr -P add local address\n" " --del-laddr -Q del local address\n" " --get-laddr -G get local address\n" - " --add-blklst -U add blacklist address\n" - " --del-blklst -V del blacklist address\n" - " --get-blklst -B get blacklist address\n" - " --add-whtlst -O add whitelist address\n" - " --del-whtlst -Y del whitelist address\n" - " --get-whtlst -W get whitelist address\n" + " --add-blklst -U add blacklist address or ipset\n" + " --del-blklst -V del blacklist address or ipset\n" + " --get-blklst -B get blacklist address or ipset\n" + " --add-whtlst -O add whitelist address or ipset\n" + " --del-whtlst -Y del whitelist address or ipset\n" + " --get-whtlst -W get whitelist address or ipset\n" " --save -S save rules to stdout\n" " --add-server -a add real server with options\n" " --edit-server -e edit real server with options\n" @@ -1752,8 +1760,8 @@ static void usage_exit(const char *program, const int exit_status) " UPDOWN:=down_retry,up_confirm,down_wait,inhibit_min-inhibit_max, for example, the default is 1,1,3s,5-3600s\n" " DOWNONLY:=down_retry,down_wait, for example, --dest-check=1,3s\n" " --laddr -z local-ip local IP\n" - " --blklst -k blacklist-ip blacklist IP for specific service\n" - " --whtlst -2 whitelist-ip whitelist IP for specific service\n" + " --blklst -k blacklist-ip specify blacklist ip address or ipset(format: \"ipset:NAME\")\n" + " --whtlst -2 whitelist-ip specify whitelist ip address or ipset(format: \"ipset:NAME\")\n" " --quic itef quic protocol service\n", DEF_SCHED); @@ -2423,17 +2431,16 @@ static int list_all_laddrs(lcoreid_t index) static void list_blklsts_print_title(void) { - printf("%-20s %-8s %-20s\n", - "VIP:VPORT" , + printf("%-8s %-30s %-30s\n", "PROTO" , + "VIP:VPORT" , "BLACKLIST"); } -static void print_service_and_blklsts(struct dp_vs_blklst_conf *blklst) +static void print_service_and_blklsts(const struct dp_vs_blklst_conf *blklst) { - char vip[64], bip[64], port[8], proto[8]; - const char *pattern = (blklst->af == AF_INET ? - "%s:%-8s %-8s %-20s\n" : "[%s]:%-8s %-8s %-20s\n"); + char subject[64], vip[64], vport[8], proto[8], vip_port[64]; + const char *pattern = "%-8s %-30s %-30s\n"; switch (blklst->proto) { case IPPROTO_TCP: @@ -2455,10 +2462,19 @@ static void print_service_and_blklsts(struct dp_vs_blklst_conf *blklst) break; } - snprintf(port, sizeof(port), "%u", ntohs(blklst->vport)); + snprintf(vport, sizeof(vport), "%u", ntohs(blklst->vport)); + inet_ntop(blklst->af, (const void *)&blklst->vaddr, vip, sizeof(vip)); + if (blklst->af == AF_INET6) + snprintf(vip_port, sizeof(vip_port), "[%s]:%s", vip, vport); + else + snprintf(vip_port, sizeof(vip_port), "%s:%s", vip, vport); + + if (blklst->ipset[0] == '\0') + inet_ntop(blklst->af, (const void *)&blklst->subject, subject, sizeof(subject)); + else + snprintf(subject, sizeof(subject), "ipset:%s", blklst->ipset); - printf(pattern, inet_ntop(blklst->af, (const void *)&blklst->vaddr, vip, sizeof(vip)), - port, proto, inet_ntop(blklst->af, (const void *)&blklst->blklst, bip, sizeof(bip))); + printf(pattern, proto, vip_port, subject); } static bool inet_addr_equal(int af, const union inet_addr *a1, const union inet_addr *a2) @@ -2473,9 +2489,20 @@ static bool inet_addr_equal(int af, const union inet_addr *a1, const union inet_ } } -static int list_blklst(int af, const union inet_addr *addr, uint16_t port, uint16_t protocol) +static inline void __list_blklst(int af, const union inet_addr *addr, uint16_t port, + uint16_t protocol, const struct dp_vs_blklst_conf_array *cfarr) { int i; + for (i = 0; i < cfarr->naddr; i++) { + if (inet_addr_equal(af, addr, (const union inet_addr *) &cfarr->blklsts[i].vaddr) && + port == cfarr->blklsts[i].vport && protocol == cfarr->blklsts[i].proto) { + print_service_and_blklsts(&cfarr->blklsts[i]); + } + } +} + +static int list_blklst(int af, const union inet_addr *addr, uint16_t port, uint16_t protocol) +{ struct dp_vs_blklst_conf_array *get; if (!(get = dpvs_get_blklsts())) { @@ -2483,21 +2510,17 @@ static int list_blklst(int af, const union inet_addr *addr, uint16_t port, uint1 return -1; } - for (i = 0; i < get->naddr; i++) { - if (inet_addr_equal(af, addr,(const union inet_addr *) &get->blklsts[i].vaddr) && - port == get->blklsts[i].vport && protocol == get->blklsts[i].proto) { - print_service_and_blklsts(&get->blklsts[i]); - } - } - free(get); + __list_blklst(af, addr, port, protocol, get); + free(get); return 0; } static int list_all_blklsts(void) { int i; - dpvs_services_front_t* table; + dpvs_services_front_t *table; + struct dp_vs_blklst_conf_array *barray; table = (dpvs_services_front_t*)malloc(sizeof(dpvs_services_front_t)+sizeof(dpvs_service_compat_t)*g_ipvs_info.num_services); if (!table) { @@ -2513,12 +2536,18 @@ static int list_all_blklsts(void) exit(1); } + if(!(barray = dpvs_get_blklsts())) { + fprintf(stderr, "%s\n", ipvs_strerror(errno)); + exit(1); + } + list_blklsts_print_title(); for (i = 0; i < table->count; i++) { - list_blklst(table->entrytable[i].af, &table->entrytable[i].addr, - table->entrytable[i].port, table->entrytable[i].proto); + __list_blklst(table->entrytable[i].af, &table->entrytable[i].addr, + table->entrytable[i].port, table->entrytable[i].proto, barray); } + free(barray); free(table); return 0; @@ -2526,17 +2555,16 @@ static int list_all_blklsts(void) static void list_whtlsts_print_title(void) { - printf("%-20s %-8s %-20s\n" , - "VIP:VPORT" , + printf("%-8s %-30s %-30s\n" , "PROTO" , + "VIP:VPORT" , "WHITELIST"); } -static void print_service_and_whtlsts(struct dp_vs_whtlst_conf *whtlst) +static void print_service_and_whtlsts(const struct dp_vs_whtlst_conf *whtlst) { - char vip[64], bip[64], port[8], proto[8]; - const char *pattern = (whtlst->af == AF_INET ? - "%s:%-8s %-8s %-20s\n" : "[%s]:%-8s %-8s %-20s\n"); + char subject[64], vip[64], vport[8], proto[8], vip_port[64]; + const char *pattern = "%-8s %-30s %-30s\n"; switch (whtlst->proto) { case IPPROTO_TCP: @@ -2558,15 +2586,35 @@ static void print_service_and_whtlsts(struct dp_vs_whtlst_conf *whtlst) break; } - snprintf(port, sizeof(port), "%u", ntohs(whtlst->vport)); + snprintf(vport, sizeof(vport), "%u", ntohs(whtlst->vport)); + inet_ntop(whtlst->af, (const void *)&whtlst->vaddr, vip, sizeof(vip)); + if (whtlst->af == AF_INET6) + snprintf(vip_port, sizeof(vip_port), "[%s]:%s", vip, vport); + else + snprintf(vip_port, sizeof(vip_port), "%s:%s", vip, vport); + + if (whtlst->ipset[0] == '\0') + inet_ntop(whtlst->af, (const void *)&whtlst->subject, subject, sizeof(subject)); + else + snprintf(subject, sizeof(subject), "ipset:%s", whtlst->ipset); - printf(pattern, inet_ntop(whtlst->af, (const void *)&whtlst->vaddr, vip, sizeof(vip)), - port, proto, inet_ntop(whtlst->af, (const void *)&whtlst->whtlst, bip, sizeof(bip))); + printf(pattern, proto, vip_port, subject); } -static int list_whtlst(int af, const union inet_addr *addr, uint16_t port, uint16_t protocol) +static inline void __list_whtlst(int af, const union inet_addr *addr, uint16_t port, + uint16_t protocol, const struct dp_vs_whtlst_conf_array *cfarr) { int i; + for (i = 0; i < cfarr->naddr; i++) { + if (inet_addr_equal(af, addr,(const union inet_addr *) &cfarr->whtlsts[i].vaddr) && + port == cfarr->whtlsts[i].vport && protocol == cfarr->whtlsts[i].proto) { + print_service_and_whtlsts(&cfarr->whtlsts[i]); + } + } +} + +static int list_whtlst(int af, const union inet_addr *addr, uint16_t port, uint16_t protocol) +{ struct dp_vs_whtlst_conf_array *get; if (!(get = dpvs_get_whtlsts())) { @@ -2574,22 +2622,17 @@ static int list_whtlst(int af, const union inet_addr *addr, uint16_t port, uint1 return -1; } - for (i = 0; i < get->naddr; i++) { - if (inet_addr_equal(af, addr,(const union inet_addr *) &get->whtlsts[i].vaddr) && - port == get->whtlsts[i].vport && protocol == get->whtlsts[i].proto) { - print_service_and_whtlsts(&get->whtlsts[i]); - } - } + __list_whtlst(af, addr, port, protocol, get); free(get); - return 0; } static int list_all_whtlsts(void) { - dpvs_services_front_t* table; int i; + dpvs_services_front_t *table; + struct dp_vs_whtlst_conf_array *warray; table = (dpvs_services_front_t*)malloc(sizeof(dpvs_services_front_t)+sizeof(dpvs_service_compat_t)*g_ipvs_info.num_services); if (!table) { @@ -2605,12 +2648,18 @@ static int list_all_whtlsts(void) exit(1); } + if (!(warray = dpvs_get_whtlsts())) { + fprintf(stderr, "%s\n", ipvs_strerror(errno)); + exit(1); + } + list_whtlsts_print_title(); for (i = 0; i < table->count; i++) { - list_whtlst(table->entrytable[i].af, &table->entrytable[i].addr, - table->entrytable[i].port, table->entrytable[i].proto); + __list_whtlst(table->entrytable[i].af, &table->entrytable[i].addr, + table->entrytable[i].port, table->entrytable[i].proto, warray); } + free(warray); free(table); return 0; diff --git a/tools/keepalived/keepalived/check/check_data.c b/tools/keepalived/keepalived/check/check_data.c index 95db23d39..679a7653a 100644 --- a/tools/keepalived/keepalived/check/check_data.c +++ b/tools/keepalived/keepalived/check/check_data.c @@ -106,8 +106,10 @@ free_whtlst_group(void *data) FREE_PTR(whtlst_group->gname); free_list(&whtlst_group->addr_ip); free_list(&whtlst_group->range); + free_list(&whtlst_group->ipset); FREE(whtlst_group); } + static void dump_whtlst_group(FILE *fp, const void *data) { @@ -116,18 +118,23 @@ dump_whtlst_group(FILE *fp, const void *data) conf_write(fp, " whitelist IP address group = %s", whtlst_group->gname); dump_list(fp, whtlst_group->addr_ip); dump_list(fp, whtlst_group->range); + dump_list(fp, whtlst_group->ipset); } + static void free_whtlst_entry(void *data) { FREE(data); } + static void dump_whtlst_entry(FILE *fp, const void *data) { const whtlst_addr_entry *whtlst_entry = data; - if (whtlst_entry->range) + if (!strncmp(whtlst_entry->ipset, "ipset:", sizeof("ipset:") - 1)) + conf_write(fp, " IPSET = %s", whtlst_entry->ipset); + else if (whtlst_entry->range) conf_write(fp, " IP Range = %s-%d" , inet_sockaddrtos(&whtlst_entry->addr) , whtlst_entry->range); @@ -135,6 +142,7 @@ dump_whtlst_entry(FILE *fp, const void *data) conf_write(fp, " IP = %s" , inet_sockaddrtos(&whtlst_entry->addr)); } + void alloc_whtlst_group(char *gname) { @@ -146,21 +154,33 @@ alloc_whtlst_group(char *gname) memcpy(new->gname, gname, size); new->addr_ip = alloc_list(free_whtlst_entry, dump_whtlst_entry); new->range = alloc_list(free_whtlst_entry, dump_whtlst_entry); + new->ipset = alloc_list(free_whtlst_entry, dump_whtlst_entry); list_add(check_data->whtlst_group, new); } + void alloc_whtlst_entry(const vector_t *strvec) { whtlst_addr_group *whtlst_group = LIST_TAIL_DATA(check_data->whtlst_group); whtlst_addr_entry *new; + const char *str_entry; new = (whtlst_addr_entry *) MALLOC(sizeof (whtlst_addr_entry)); + if (!new) + return; + str_entry = strvec_slot(strvec, 0); + + if (!strncmp(str_entry, "ipset:", sizeof("ipset:") - 1)) { + strncpy(new->ipset, &str_entry[sizeof("ipset:")-1], sizeof(new->ipset) - 1); + list_add(whtlst_group->ipset, new); + return; + } - inet_stor(vector_slot(strvec, 0), &new->range); + inet_stor(str_entry, &new->range); if (new->range == UINT32_MAX) new->range = 0; - inet_stosockaddr(vector_slot(strvec, 0), NULL, &new->addr); + inet_stosockaddr(str_entry, NULL, &new->addr); if (!new->range) list_add(whtlst_group->addr_ip, new); @@ -257,7 +277,6 @@ alloc_vsg_entry(const vector_t *strvec) unsigned fwmark; new = (virtual_server_group_entry_t *) MALLOC(sizeof(virtual_server_group_entry_t)); - if (!strcmp(strvec_slot(strvec, 0), "fwmark")) { if (!read_unsigned_strvec(strvec, 1, &fwmark, 0, UINT32_MAX, true)) { report_config_error(CONFIG_GENERAL_ERROR, "(%s): fwmark '%s' must be in [0, %u] - ignoring", vsg->gname, strvec_slot(strvec, 1), UINT32_MAX); @@ -508,8 +527,11 @@ dump_vs(FILE *fp, const void *data) if (vs->blklst_addr_gname) conf_write(fp, " BLACK_LIST GROUP = %s", vs->blklst_addr_gname); + if (vs->whtlst_addr_gname) + conf_write(fp, " WHITE_LIST GROUP = %s", vs->whtlst_addr_gname); + if (vs->vip_bind_dev) - conf_write(fp, " vip_bind_dev = %s", vs->blklst_addr_gname); + conf_write(fp, " vip_bind_dev = %s", vs->vip_bind_dev); conf_write(fp, " SYN proxy is %s", vs->syn_proxy ? "ON" : "OFF"); conf_write(fp, " expire_quiescent_conn is %s", vs->expire_quiescent_conn ? "ON" : "OFF"); @@ -560,8 +582,7 @@ alloc_vs(const char *param1, const char *param2) new->vfwmark = fwmark; } else if (!strcmp(param1, "match")) { - new->forwarding_method = IP_VS_CONN_F_SNAT; - + new->forwarding_method = IP_VS_CONN_F_SNAT; } else { /* Don't pass a zero for port number to inet_stosockaddr. This was added in v2.0.7 * to support legacy configuration since previously having no port wasn't allowed. */ @@ -622,8 +643,8 @@ alloc_vs(const char *param1, const char *param2) } /*local address group facility functions*/ -static void -free_laddr_group(void *data) +static void +free_laddr_group(void *data) { local_addr_group *laddr_group = (local_addr_group*)data; FREE_PTR(laddr_group->gname); @@ -708,6 +729,7 @@ free_blklst_group(void *data) FREE_PTR(blklst_group->gname); free_list(&blklst_group->addr_ip); free_list(&blklst_group->range); + free_list(&blklst_group->ipset); FREE(blklst_group); } @@ -719,6 +741,7 @@ dump_blklst_group(FILE *fp, const void *data) conf_write(fp, " blacllist IP address group = %s", blklst_group->gname); dump_list(fp, blklst_group->addr_ip); dump_list(fp, blklst_group->range); + dump_list(fp, blklst_group->ipset); } static void @@ -732,7 +755,9 @@ dump_blklst_entry(FILE *fp, const void *data) { const blklst_addr_entry *blklst_entry = data; - if (blklst_entry->range) + if (!strncmp(blklst_entry->ipset, "ipset:", sizeof("ipset:") - 1)) + conf_write(fp, " IPSET = %s", blklst_entry->ipset); + else if (blklst_entry->range) conf_write(fp, " IP Range = %s-%d" , inet_sockaddrtos(&blklst_entry->addr) , blklst_entry->range); @@ -752,6 +777,7 @@ alloc_blklst_group(char *gname) memcpy(new->gname, gname, size); new->addr_ip = alloc_list(free_blklst_entry, dump_blklst_entry); new->range = alloc_list(free_blklst_entry, dump_blklst_entry); + new->ipset = alloc_list(free_blklst_entry, dump_blklst_entry); list_add(check_data->blklst_group, new); } @@ -761,14 +787,24 @@ alloc_blklst_entry(const vector_t *strvec) { blklst_addr_group *blklst_group = LIST_TAIL_DATA(check_data->blklst_group); blklst_addr_entry *new; + const char *str_entry; new = (blklst_addr_entry *) MALLOC(sizeof (blklst_addr_entry)); + if (!new) + return; + str_entry = strvec_slot(strvec, 0); - inet_stor(vector_slot(strvec, 0), &new->range); + if (!strncmp(str_entry, "ipset:", sizeof("ipset:") - 1)) { + strncpy(new->ipset, &str_entry[sizeof("ipset:")-1], sizeof(new->ipset) - 1); + list_add(blklst_group->ipset, new); + return; + } + + inet_stor(str_entry, &new->range); /* If no range specified, new->range == UINT32_MAX */ if (new->range == UINT32_MAX) new->range = 0; - inet_stosockaddr(vector_slot(strvec, 0), NULL, &new->addr); + inet_stosockaddr(str_entry, NULL, &new->addr); if (!new->range) list_add(blklst_group->addr_ip, new); @@ -1052,7 +1088,7 @@ alloc_check_data(void) #endif new->laddr_group = alloc_list(free_laddr_group, dump_laddr_group); new->blklst_group = alloc_list(free_blklst_group, dump_blklst_group); - new->whtlst_group = alloc_list(free_whtlst_group, dump_whtlst_group); + new->whtlst_group = alloc_list(free_whtlst_group, dump_whtlst_group); new->tunnel_group = alloc_list(free_tunnel_group, dump_tunnel_group); return new; @@ -1070,6 +1106,7 @@ free_check_data(check_data_t *data) #endif free_list(&data->laddr_group); free_list(&data->blklst_group); + free_list(&data->whtlst_group); free_list(&data->tunnel_group); FREE(data); } @@ -1089,6 +1126,8 @@ dump_check_data(FILE *fp, check_data_t *data) dump_list(fp, data->laddr_group); if (!LIST_ISEMPTY(data->blklst_group)) dump_list(fp, data->blklst_group); + if (!LIST_ISEMPTY(data->whtlst_group)) + dump_list(fp, data->whtlst_group); if (!LIST_ISEMPTY(data->vs_group)) dump_list(fp, data->vs_group); dump_list(fp, data->vs); diff --git a/tools/keepalived/keepalived/check/ipvswrapper.c b/tools/keepalived/keepalived/check/ipvswrapper.c index d3cb4dbd4..9a1398da4 100755 --- a/tools/keepalived/keepalived/check/ipvswrapper.c +++ b/tools/keepalived/keepalived/check/ipvswrapper.c @@ -615,8 +615,8 @@ ipvs_blklst_range_cmd(int cmd, blklst_addr_entry *blklst_entry, dpvs_service_com memset(&blklst_rule, 0, sizeof(dpvs_blklst_t)); blklst_rule.af = blklst_entry->addr.ss_family; if (blklst_entry->addr.ss_family == AF_INET6) { - inet_sockaddrip6(&blklst_entry->addr, &blklst_rule.blklst.in6); - ip = blklst_rule.blklst.in6.s6_addr32[3]; + inet_sockaddrip6(&blklst_entry->addr, &blklst_rule.subject.in6); + ip = blklst_rule.subject.in6.s6_addr32[3]; } else { ip = inet_sockaddrip4(&blklst_entry->addr); } @@ -625,9 +625,9 @@ ipvs_blklst_range_cmd(int cmd, blklst_addr_entry *blklst_entry, dpvs_service_com ((addr_ip >> 24) & 0xFF) <= blklst_entry->range; addr_ip += 0x01000000) { if (blklst_entry->addr.ss_family == AF_INET6) - blklst_rule.blklst.in6.s6_addr32[3] = addr_ip; + blklst_rule.subject.in6.s6_addr32[3] = addr_ip; else - blklst_rule.blklst.in.s_addr = addr_ip; + blklst_rule.subject.in.s_addr = addr_ip; ipvs_talk(cmd, srule, NULL, NULL, NULL, &blklst_rule, NULL, NULL, false); } @@ -649,9 +649,9 @@ ipvs_blklst_group_cmd(int cmd, blklst_addr_group *blklst_group, dpvs_service_com memset(&blklst_rule, 0, sizeof(dpvs_blklst_t)); blklst_rule.af = blklst_entry->addr.ss_family; if (blklst_entry->addr.ss_family == AF_INET6) - inet_sockaddrip6(&blklst_entry->addr, &blklst_rule.blklst.in6); + inet_sockaddrip6(&blklst_entry->addr, &blklst_rule.subject.in6); else - blklst_rule.blklst.in.s_addr = inet_sockaddrip4(&blklst_entry->addr); + blklst_rule.subject.in.s_addr = inet_sockaddrip4(&blklst_entry->addr); ipvs_talk(cmd, srule, NULL, NULL, NULL, &blklst_rule, NULL, NULL, false); } @@ -659,6 +659,13 @@ ipvs_blklst_group_cmd(int cmd, blklst_addr_group *blklst_group, dpvs_service_com LIST_FOREACH(l, blklst_entry, e) { ipvs_blklst_range_cmd(cmd, blklst_entry, srule); } + + l = blklst_group->ipset; + LIST_FOREACH(l, blklst_entry, e) { + memset(&blklst_rule, 0, sizeof(dpvs_blklst_t)); + strncpy(blklst_rule.ipset, blklst_entry->ipset, sizeof(blklst_rule.ipset) - 1); + ipvs_talk(cmd, srule, NULL, NULL, NULL, &blklst_rule, NULL, NULL, false); + } } static void @@ -858,8 +865,8 @@ ipvs_whtlst_range_cmd(int cmd, whtlst_addr_entry *whtlst_entry, dpvs_service_com memset(&whtlst_rule, 0, sizeof(dpvs_whtlst_t)); whtlst_rule.af = whtlst_entry->addr.ss_family; if (whtlst_entry->addr.ss_family == AF_INET6) { - inet_sockaddrip6(&whtlst_entry->addr, &whtlst_rule.whtlst.in6); - ip = whtlst_rule.whtlst.in6.s6_addr32[3]; + inet_sockaddrip6(&whtlst_entry->addr, &whtlst_rule.subject.in6); + ip = whtlst_rule.subject.in6.s6_addr32[3]; } else { ip = inet_sockaddrip4(&whtlst_entry->addr); } @@ -867,9 +874,9 @@ ipvs_whtlst_range_cmd(int cmd, whtlst_addr_entry *whtlst_entry, dpvs_service_com for (addr_ip = ip; ((addr_ip >> 24) & 0xFF) <= whtlst_entry->range; addr_ip += 0x01000000) { if (whtlst_entry->addr.ss_family == AF_INET6) - whtlst_rule.whtlst.in6.s6_addr32[3] = addr_ip; + whtlst_rule.subject.in6.s6_addr32[3] = addr_ip; else - whtlst_rule.whtlst.in.s_addr = addr_ip; + whtlst_rule.subject.in.s_addr = addr_ip; ipvs_talk(cmd, srule, NULL, NULL, NULL, NULL, &whtlst_rule, NULL, false); } @@ -891,9 +898,9 @@ ipvs_whtlst_group_cmd(int cmd, whtlst_addr_group *whtlst_group, dpvs_service_com memset(&whtlst_rule, 0, sizeof(dpvs_whtlst_t)); whtlst_rule.af = whtlst_entry->addr.ss_family; if (whtlst_entry->addr.ss_family == AF_INET6) - inet_sockaddrip6(&whtlst_entry->addr, &whtlst_rule.whtlst.in6); + inet_sockaddrip6(&whtlst_entry->addr, &whtlst_rule.subject.in6); else - whtlst_rule.whtlst.in.s_addr = inet_sockaddrip4(&whtlst_entry->addr); + whtlst_rule.subject.in.s_addr = inet_sockaddrip4(&whtlst_entry->addr); ipvs_talk(cmd, srule, NULL, NULL, NULL, NULL, &whtlst_rule, NULL, false); } @@ -901,6 +908,13 @@ ipvs_whtlst_group_cmd(int cmd, whtlst_addr_group *whtlst_group, dpvs_service_com LIST_FOREACH(l, whtlst_entry, e) { ipvs_whtlst_range_cmd(cmd, whtlst_entry, srule); } + + l = whtlst_group->ipset; + LIST_FOREACH(l, whtlst_entry, e) { + memset(&whtlst_rule, 0, sizeof(dpvs_whtlst_t)); + strncpy(whtlst_rule.ipset, whtlst_entry->ipset, sizeof(whtlst_rule.ipset) - 1); + ipvs_talk(cmd, srule, NULL, NULL, NULL, NULL, &whtlst_rule, NULL, false); + } } static void @@ -1281,29 +1295,36 @@ ipvs_rm_bentry_from_vsg(blklst_addr_entry *blklst_entry, whtlst_addr_entry *whtl srule->addr.in.s_addr = ip; if (blklst_entry != NULL) { - if (blklst_entry->range) + if(blklst_entry->ipset[0] != '\0') { + memset(&blklst_rule, 0, sizeof(dpvs_blklst_t)); + strncpy(blklst_rule.ipset, blklst_entry->ipset, sizeof(blklst_rule.ipset) - 1); + ipvs_talk(IP_VS_SO_SET_DELBLKLST, srule, NULL, NULL, NULL, &blklst_rule, NULL, NULL, false); + } else if (blklst_entry->range) { ipvs_blklst_range_cmd(IP_VS_SO_SET_DELBLKLST, blklst_entry, srule); - else { + } else { memset(&blklst_rule, 0, sizeof(dpvs_blklst_t)); blklst_rule.af = blklst_entry->addr.ss_family; if (blklst_entry->addr.ss_family == AF_INET6) - inet_sockaddrip6(&blklst_entry->addr, &blklst_rule.blklst.in6); + inet_sockaddrip6(&blklst_entry->addr, &blklst_rule.subject.in6); else - blklst_rule.blklst.in.s_addr = inet_sockaddrip4(&blklst_entry->addr); + blklst_rule.subject.in.s_addr = inet_sockaddrip4(&blklst_entry->addr); ipvs_talk(IP_VS_SO_SET_DELBLKLST, srule, NULL, NULL, NULL, &blklst_rule, NULL, NULL, false); } } if (whtlst_entry != NULL) { - if (whtlst_entry->range) + if (whtlst_entry->ipset[0] != '\0') { + memset(&whtlst_rule, 0, sizeof(dpvs_whtlst_t)); + strncpy(whtlst_rule.ipset, whtlst_entry->ipset, sizeof(whtlst_rule.ipset) - 1); + ipvs_talk(IP_VS_SO_SET_DELWHTLST, srule, NULL, NULL, NULL, NULL, &whtlst_rule, NULL, false); + } else if (whtlst_entry->range) { ipvs_whtlst_range_cmd(IP_VS_SO_SET_DELWHTLST, whtlst_entry, srule); - else { + } else { memset(&whtlst_rule, 0, sizeof(dpvs_whtlst_t)); whtlst_rule.af = whtlst_entry->addr.ss_family; if (whtlst_entry->addr.ss_family == AF_INET6) - inet_sockaddrip6(&whtlst_entry->addr, &whtlst_rule.whtlst.in6); + inet_sockaddrip6(&whtlst_entry->addr, &whtlst_rule.subject.in6); else - whtlst_rule.whtlst.in.s_addr = inet_sockaddrip4(&whtlst_entry->addr); - + whtlst_rule.subject.in.s_addr = inet_sockaddrip4(&whtlst_entry->addr); ipvs_talk(IP_VS_SO_SET_DELWHTLST, srule, NULL, NULL, NULL, NULL, &whtlst_rule, NULL, false); } } @@ -1319,31 +1340,37 @@ ipvs_rm_bentry_from_vsg(blklst_addr_entry *blklst_entry, whtlst_addr_entry *whtl srule->addr.in.s_addr = addr_ip; if (blklst_entry != NULL) { - if (blklst_entry->range) + if(blklst_entry->ipset[0] != '\0') { + memset(&blklst_rule, 0, sizeof(dpvs_blklst_t)); + strncpy(blklst_rule.ipset, blklst_entry->ipset, sizeof(blklst_rule.ipset) - 1); + ipvs_talk(IP_VS_SO_SET_DELBLKLST, srule, NULL, NULL, NULL, &blklst_rule, NULL, NULL, false); + } else if (blklst_entry->range) { ipvs_blklst_range_cmd(IP_VS_SO_SET_DELBLKLST, blklst_entry, srule); - else { + } else { memset(&blklst_rule, 0, sizeof(dpvs_blklst_t)); blklst_rule.af = blklst_entry->addr.ss_family; if (blklst_entry->addr.ss_family == AF_INET6) - inet_sockaddrip6(&blklst_entry->addr, &blklst_rule.blklst.in6); + inet_sockaddrip6(&blklst_entry->addr, &blklst_rule.subject.in6); else - blklst_rule.blklst.in.s_addr = inet_sockaddrip4(&blklst_entry->addr); + blklst_rule.subject.in.s_addr = inet_sockaddrip4(&blklst_entry->addr); ipvs_talk(IP_VS_SO_SET_DELBLKLST, srule, NULL, NULL, NULL, &blklst_rule, NULL, NULL, false); } } - if (whtlst_entry != NULL) - { - if (whtlst_entry->range) + if (whtlst_entry != NULL) { + if (whtlst_entry->ipset[0] != '\0') { + memset(&whtlst_rule, 0, sizeof(dpvs_whtlst_t)); + strncpy(whtlst_rule.ipset, whtlst_entry->ipset, sizeof(whtlst_rule.ipset) - 1); + ipvs_talk(IP_VS_SO_SET_DELWHTLST, srule, NULL, NULL, NULL, NULL, &whtlst_rule, NULL, false); + } else if (whtlst_entry->range) { ipvs_whtlst_range_cmd(IP_VS_SO_SET_DELWHTLST, whtlst_entry, srule); - else { + } else { memset(&whtlst_rule, 0, sizeof(dpvs_whtlst_t)); whtlst_rule.af = whtlst_entry->addr.ss_family; if (whtlst_entry->addr.ss_family == AF_INET6) - inet_sockaddrip6(&whtlst_entry->addr, &whtlst_rule.whtlst.in6); + inet_sockaddrip6(&whtlst_entry->addr, &whtlst_rule.subject.in6); else - whtlst_rule.whtlst.in.s_addr = inet_sockaddrip4(&whtlst_entry->addr); - + whtlst_rule.subject.in.s_addr = inet_sockaddrip4(&whtlst_entry->addr); ipvs_talk(IP_VS_SO_SET_DELWHTLST, srule, NULL, NULL, NULL, NULL, &whtlst_rule, NULL, false); } } @@ -1373,15 +1400,19 @@ ipvs_blklst_remove_entry(virtual_server_t *vs, blklst_addr_entry *blklst_entry) } srule.port = inet_sockaddrport(&vs->addr); - if (blklst_entry->range) { + if(blklst_entry->ipset[0] != '\0') { + memset(&blklst_rule, 0, sizeof(dpvs_blklst_t)); + strncpy(blklst_rule.ipset, blklst_entry->ipset, sizeof(blklst_rule.ipset) - 1); + ipvs_talk(IP_VS_SO_SET_DELBLKLST, &srule, NULL, NULL, NULL, &blklst_rule, NULL, NULL, false); + } else if (blklst_entry->range) { ipvs_blklst_range_cmd(IP_VS_SO_SET_DELBLKLST, blklst_entry, &srule); } else { memset(&blklst_rule, 0, sizeof(dpvs_blklst_t)); blklst_rule.af = blklst_entry->addr.ss_family; if (blklst_entry->addr.ss_family == AF_INET6) - inet_sockaddrip6(&blklst_entry->addr, &blklst_rule.blklst.in6); + inet_sockaddrip6(&blklst_entry->addr, &blklst_rule.subject.in6); else - blklst_rule.blklst.in.s_addr = inet_sockaddrip4(&blklst_entry->addr); + blklst_rule.subject.in.s_addr = inet_sockaddrip4(&blklst_entry->addr); ipvs_talk(IP_VS_SO_SET_DELBLKLST, &srule, NULL, NULL, NULL, &blklst_rule, NULL, NULL, false); } @@ -1412,15 +1443,19 @@ ipvs_whtlst_remove_entry(virtual_server_t *vs, whtlst_addr_entry *whtlst_entry) } srule.port = inet_sockaddrport(&vs->addr); - if (whtlst_entry->range) { + if (whtlst_entry->ipset[0] != '\0') { + memset(&whtlst_rule, 0, sizeof(dpvs_whtlst_t)); + strncpy(whtlst_rule.ipset, whtlst_entry->ipset, sizeof(whtlst_rule.ipset) - 1); + ipvs_talk(IP_VS_SO_SET_DELWHTLST, &srule, NULL, NULL, NULL, NULL, &whtlst_rule, NULL, false); + } else if (whtlst_entry->range) { ipvs_whtlst_range_cmd(IP_VS_SO_SET_DELWHTLST, whtlst_entry, &srule); } else { memset(&whtlst_rule, 0, sizeof(dpvs_whtlst_t)); whtlst_rule.af = whtlst_entry->addr.ss_family; if (whtlst_entry->addr.ss_family == AF_INET6) - inet_sockaddrip6(&whtlst_entry->addr, &whtlst_rule.whtlst.in6); + inet_sockaddrip6(&whtlst_entry->addr, &whtlst_rule.subject.in6); else - whtlst_rule.whtlst.in.s_addr = inet_sockaddrip4(&whtlst_entry->addr); + whtlst_rule.subject.in.s_addr = inet_sockaddrip4(&whtlst_entry->addr); ipvs_talk(IP_VS_SO_SET_DELWHTLST, &srule, NULL, NULL, NULL, NULL, &whtlst_rule, NULL, false); } diff --git a/tools/keepalived/keepalived/check/ipwrapper.c b/tools/keepalived/keepalived/check/ipwrapper.c index 7bc45d1c2..8b3fc470d 100755 --- a/tools/keepalived/keepalived/check/ipwrapper.c +++ b/tools/keepalived/keepalived/check/ipwrapper.c @@ -1171,7 +1171,8 @@ blklst_entry_exist(blklst_addr_entry *blklst_entry, list l) LIST_FOREACH(l, entry, e) { if (sockstorage_equal(&entry->addr, &blklst_entry->addr) && - entry->range == blklst_entry->range) + entry->range == blklst_entry->range && + !strncmp(entry->ipset, blklst_entry->ipset, sizeof(entry->ipset))) return 1; } return 0; @@ -1234,25 +1235,27 @@ clear_diff_blklst(virtual_server_t * old_vs, virtual_server_t * new_vs) if (!old) return 1; + if (new_vs->blklst_addr_gname) + new = ipvs_get_blklst_group_by_name(new_vs->blklst_addr_gname, + check_data->blklst_group); + /* if new_vs has no blacklist group, delete all blklst address from old_vs */ - if (!new_vs->blklst_addr_gname) { + if (!new) { if (!clear_all_blklst_entry(old->addr_ip, old_vs)) return 0; if (!clear_all_blklst_entry(old->range, old_vs)) return 0; + if (!clear_all_blklst_entry(old->ipset, old_vs)) + return 0; return 1; } - else - /* Fetch new_vs blacklist address group */ - new = ipvs_get_blklst_group_by_name(new_vs->blklst_addr_gname, - check_data->blklst_group); - if (!new) - return 1; if (!clear_diff_blklst_entry(old->addr_ip, new->addr_ip, old_vs)) return 0; if (!clear_diff_blklst_entry(old->range, new->range, old_vs)) return 0; + if (!clear_diff_blklst_entry(old->ipset, new->ipset, old_vs)) + return 0; return 1; } @@ -1267,8 +1270,9 @@ whtlst_entry_exist(whtlst_addr_entry *whtlst_entry, list l) for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { entry = ELEMENT_DATA(e); if (sockstorage_equal(&entry->addr, &whtlst_entry->addr) && - entry->range == whtlst_entry->range) - return 1; + entry->range == whtlst_entry->range && + !strncmp(entry->ipset, whtlst_entry->ipset, sizeof(entry->ipset))) + return 1; } return 0; } @@ -1327,28 +1331,30 @@ clear_diff_whtlst(virtual_server_t * old_vs, virtual_server_t * new_vs) /* Fetch whitelist address group */ old = ipvs_get_whtlst_group_by_name(old_vs->whtlst_addr_gname, old_check_data->whtlst_group); - if (!old) return 1; + + if (new_vs->whtlst_addr_gname) + new = ipvs_get_whtlst_group_by_name(new_vs->whtlst_addr_gname, + check_data->whtlst_group); + /* if new_vs has no whitelist group, delete all whtlst address from old_vs */ - if (!new_vs->whtlst_addr_gname) { + if (!new) { if (!clear_all_whtlst_entry(old->addr_ip, old_vs)) return 0; if (!clear_all_whtlst_entry(old->range, old_vs)) return 0; + if (!clear_all_whtlst_entry(old->ipset, old_vs)) + return 0; return 1; } - else - /* Fetch new_vs whitelist address group */ - new = ipvs_get_whtlst_group_by_name(new_vs->whtlst_addr_gname, - check_data->whtlst_group); - if (!new) - return 1; if (!clear_diff_whtlst_entry(old->addr_ip, new->addr_ip, old_vs)) return 0; if (!clear_diff_whtlst_entry(old->range, new->range, old_vs)) return 0; + if (!clear_diff_whtlst_entry(old->ipset, new->ipset, old_vs)) + return 0; return 1; } diff --git a/tools/keepalived/keepalived/check/libipvs.c b/tools/keepalived/keepalived/check/libipvs.c index 849ac51ad..08e41ed0f 100644 --- a/tools/keepalived/keepalived/check/libipvs.c +++ b/tools/keepalived/keepalived/check/libipvs.c @@ -299,17 +299,10 @@ int dpvs_del_laddr(dpvs_service_compat_t *svc, dpvs_laddr_table_t *laddr) /*for black list*/ static void dpvs_fill_blklst_conf(dpvs_service_compat_t *svc, dpvs_blklst_t *blklst) { - blklst->af = svc->af; - blklst->proto = svc->proto; - blklst->vport = svc->port; - blklst->fwmark = svc->fwmark; - if (svc->af == AF_INET) { - blklst->vaddr.in = svc->addr.in; - } else { - blklst->vaddr.in6 = svc->addr.in6; - } - - return; + blklst->af = svc->af; + blklst->proto = svc->proto; + blklst->vport = svc->port; + blklst->vaddr = svc->addr; } int dpvs_add_blklst(dpvs_service_compat_t* svc, dpvs_blklst_t *blklst) @@ -336,14 +329,7 @@ static void dpvs_fill_whtlst_conf(dpvs_service_compat_t *svc, dpvs_whtlst_t *wht whtlst->af = svc->af; whtlst->proto = svc->proto; whtlst->vport = svc->port; - whtlst->fwmark = svc->fwmark; - if (svc->af == AF_INET) { - whtlst->vaddr.in = svc->addr.in; - } else { - whtlst->vaddr.in6 = svc->addr.in6; - } - - return; + whtlst->vaddr = svc->addr; } int dpvs_add_whtlst(dpvs_service_compat_t* svc, dpvs_whtlst_t *whtlst) diff --git a/tools/keepalived/keepalived/include/check_data.h b/tools/keepalived/keepalived/include/check_data.h index 14650b644..6b32141e6 100644 --- a/tools/keepalived/keepalived/include/check_data.h +++ b/tools/keepalived/keepalived/include/check_data.h @@ -132,6 +132,7 @@ typedef struct _local_addr_group { typedef struct _blklst_addr_entry { struct sockaddr_storage addr; uint32_t range; + char ipset[IPSET_MAXNAMELEN]; } blklst_addr_entry; @@ -139,18 +140,21 @@ typedef struct _blklst_addr_group { char *gname; list addr_ip; list range; + list ipset; } blklst_addr_group; /* whitelist ip group*/ typedef struct _whtlst_addr_entry { struct sockaddr_storage addr; uint32_t range; + char ipset[IPSET_MAXNAMELEN]; } whtlst_addr_entry; typedef struct _whtlst_addr_group { char *gname; list addr_ip; list range; + list ipset; } whtlst_addr_group; typedef struct _tunnel_entry {