diff options
Diffstat (limited to 'lib/libtle_l4p/port_statmap.h')
-rw-r--r-- | lib/libtle_l4p/port_statmap.h | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/lib/libtle_l4p/port_statmap.h b/lib/libtle_l4p/port_statmap.h new file mode 100644 index 0000000..8bbb0ba --- /dev/null +++ b/lib/libtle_l4p/port_statmap.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2019 Ant Financial Services Group. + * 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. + */ + +#ifndef _PORT_STATMAP_H_ +#define _PORT_STATMAP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_PORT_NUM (UINT16_MAX + 1) +#define ALLOC_PORT_START 0x8000 + +struct tle_psm { + uint32_t nb_used; /* Number of ports already in use. */ + uint32_t next_alloc; /* Next port to try allocate. */ + uint8_t stat[MAX_PORT_NUM]; /* Status of the port: + * 1) the most significant bit indicates + * if SO_REUSEPORT is allowed; + * 2) lowest 7 bits indicate # of streams + * using the port. + */ +}; + +static inline void +tle_psm_init(struct tle_psm *psm) +{ + memset(psm, 0, sizeof(struct tle_psm)); + psm->next_alloc = ALLOC_PORT_START; +} + +static inline int +tle_psm_set(struct tle_psm *psm, uint16_t port, uint8_t reuseport) +{ + if (psm->stat[port] == 0) { + /* port has not been used */ + psm->stat[port]++; + if (reuseport) + psm->stat[port] |= 0x80; + } else { + /* port is used by some socket */ + if (reuseport && (psm->stat[port] & 0x80)) { + /* all sockets set reuseport */ + psm->stat[port]++; + } else + return -1; + } + + return 0; +} + +static inline void +tle_psm_clear(struct tle_psm *psm, uint16_t port) +{ + psm->stat[port]--; + if ((psm->stat[port] & 0x7f) == 0) + psm->stat[port] = 0; +} + + +static inline uint8_t +tle_psm_check(const struct tle_psm *psm, uint16_t port) +{ + return psm->stat[port]; +} + +static inline uint16_t +tle_psm_alloc_port(struct tle_psm *psm) +{ + uint32_t i = psm->next_alloc; + + for (; i < MAX_PORT_NUM; i++) { + if (psm->stat[i] == 0) { + psm->next_alloc = i + 1; + return (uint16_t)i; + } + } + + for (i = ALLOC_PORT_START; i < psm->next_alloc; i++) { + if (psm->stat[i] == 0) { + psm->next_alloc = i + 1; + return (uint16_t)i; + } + } + + return 0; +} + +static inline uint16_t +tle_psm_alloc_dual_port(struct tle_psm *psm4, struct tle_psm *psm6) +{ + uint32_t i = psm6->next_alloc; + + for (; i < MAX_PORT_NUM; i++) { + if (psm6->stat[i] == 0 && psm4->stat[i] == 0) { + psm6->next_alloc = i + 1; + return (uint16_t)i; + } + } + + for (i = ALLOC_PORT_START; i < psm6->next_alloc; i++) { + if (psm6->stat[i] == 0 && psm4->stat[i] == 0) { + psm6->next_alloc = i + 1; + return (uint16_t)i; + } + } + + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _PORT_STATMAP_H_ */ |