DHCP Enhancements and Fixes

This commit is contained in:
Christian Giese
2021-04-29 17:50:25 +02:00
parent bd411459d5
commit b7eb68787f
8 changed files with 103 additions and 36 deletions
+5 -3
View File
@@ -455,9 +455,11 @@ This section describes all attributes of the `dhcp` hierarchy.
Attribute | Description | Default
--------- | ----------- | -------
`enable` | This option allows to enable or disable DHCP | true
**WARNING**: DHCP (IPv4) is currently not supported!
`enable` | This option allows to enable or disable DHCP | false
`broadcast` | DHCP broadcast flag | false
`timeout` | DHCP timeout in seconds | 5
`tos` | IPv4 TOS for all DHCP control traffic | 0
`vlan-priority` | VLAN PBIT for all DHCP control traffic | 0
## DHCPv6
+1 -1
View File
@@ -520,7 +520,7 @@ bbl_ctrl_job (timer_s *timer)
/* Start IPoE session by sending DHCP discovery if enabled. */
session->dhcp_state = BBL_DHCP_SELECTING;
session->dhcp_xid = rand();
session->send_requests |= BBL_SEND_DHCPREQUEST;
session->send_requests |= BBL_SEND_DHCP_REQUEST;
} else if (session->ip_address && session->peer_ip_address) {
/* Start IPoE session by sending ARP request if local and
* remote IP addresses are already provided. */
+12 -4
View File
@@ -76,7 +76,7 @@
#define BBL_SEND_SESSION_IPV6PD 0x00008000
#define BBL_SEND_ARP_REQUEST 0x00010000
#define BBL_SEND_ARP_REPLY 0x00020000
#define BBL_SEND_DHCPREQUEST 0x00040000
#define BBL_SEND_DHCP_REQUEST 0x00040000
#define BBL_SEND_ICMPV6_REPLY 0x00080000
#define BBL_SEND_ICMPV6_NS 0x00100000
#define BBL_SEND_ICMPV6_NA 0x00200000
@@ -585,7 +585,7 @@ typedef struct bbl_ctx_
/* DHCP */
bool dhcp_enable;
uint16_t dhcp_timeout;
uint16_t dhcp_retry;
uint8_t dhcp_tos;
uint8_t dhcp_vlan_priority;
bool dhcp_broadcast;
@@ -670,7 +670,7 @@ typedef enum {
BBL_DHCP_REQUESTING = 2,
BBL_DHCP_BOUND = 3,
BBL_DHCP_RENEWING = 4,
BBL_DHCP_DHCPRELEASE = 5,
BBL_DHCP_RELEASE = 5,
BBL_DHCP_MAX
} __attribute__ ((__packed__)) dhcp_state_t;
@@ -833,8 +833,10 @@ typedef struct bbl_session_
uint32_t dhcp_address;
uint32_t dhcp_lease_time;
uint32_t dhcp_t1;
uint32_t dhcp_t2;
uint32_t dhcp_t2;
uint32_t dhcp_server;
uint32_t dhcp_server_identifier;
uint8_t dhcp_server_mac[ETH_ADDR_LEN];
struct timespec dhcp_lease_timestamp;
struct timespec dhcp_request_timestamp;
char *dhcp_client_identifier;
@@ -967,6 +969,12 @@ typedef struct bbl_session_
uint32_t dhcp_tx;
uint32_t dhcp_rx;
uint32_t dhcp_tx_discover;
uint32_t dhcp_rx_offer;
uint32_t dhcp_tx_request;
uint32_t dhcp_rx_ack;
uint32_t dhcp_rx_nak;
uint32_t dhcp_tx_release;
uint64_t access_ipv4_rx;
uint64_t access_ipv4_tx;
+2 -3
View File
@@ -689,9 +689,9 @@ json_parse_config (json_t *root, bbl_ctx_s *ctx) {
if (json_is_number(value)) {
ctx->config.dhcp_timeout = json_number_value(value);
}
value = json_object_get(section, "retry");
value = json_object_get(section, "tos");
if (json_is_number(value)) {
ctx->config.dhcp_retry = json_number_value(value);
ctx->config.dhcp_tos = json_number_value(value);
}
value = json_object_get(section, "vlan-priority");
if (json_is_number(value)) {
@@ -1130,7 +1130,6 @@ bbl_config_init_defaults (bbl_ctx_s *ctx) {
ctx->config.ip6cp_conf_request_retry = 10;
ctx->config.dhcp_enable = false;
ctx->config.dhcp_timeout = 5;
ctx->config.dhcp_retry = 10;
ctx->config.dhcpv6_enable = true;
ctx->config.dhcpv6_rapid_commit = true;
ctx->config.igmp_autostart = true;
+14 -8
View File
@@ -73,7 +73,7 @@ dhcp_state_string(uint32_t state) {
case BBL_DHCP_REQUESTING: return "Requesting";
case BBL_DHCP_BOUND: return "Bound";
case BBL_DHCP_RENEWING: return "Renewing";
case BBL_DHCP_DHCPRELEASE: return "Releasing";
case BBL_DHCP_RELEASE: return "Releasing";
default: return "N/A";
}
}
@@ -555,7 +555,7 @@ bbl_ctrl_session_info(int fd, bbl_ctx_s *ctx, uint32_t session_id, json_t* argum
if(seconds <= session->dhcp_lease_time) lease_expire = session->dhcp_lease_time - seconds;
if(seconds <= session->dhcp_t1) lease_expire_t1 = session->dhcp_t1 - seconds;
if(seconds <= session->dhcp_t2) lease_expire_t2 = session->dhcp_t2 - seconds;
root = json_pack("{ss si s{ss si ss ss si si ss ss* ss* ss* ss* si si si si ss* ss* ss* ss* ss* ss* ss* ss* ss* ss* ss* si si si so*}}",
root = json_pack("{ss si s{ss si ss ss si si ss ss* ss* ss* ss* ss* ss* ss* ss* ss* ss* ss* ss* ss* si si si si si si si si si si ss* ss* si si si so*}}",
"status", "ok",
"code", 200,
"session-information",
@@ -568,12 +568,6 @@ bbl_ctrl_session_info(int fd, bbl_ctx_s *ctx, uint32_t session_id, json_t* argum
"mac", format_mac_address(session->client_mac),
"agent-circuit-id", session->agent_circuit_id,
"agent-remote-id", session->agent_remote_id,
"dhcp-state", dhcp_state_string(session->dhcp_state),
"dhcp-server", format_ipv4_address(&session->dhcp_server_identifier),
"dhcp-lease-time", session->dhcp_lease_time,
"dhcp-lease-expire", lease_expire,
"dhcp-lease-expire-t1", lease_expire_t1,
"dhcp-lease-expire-t2", lease_expire_t2,
"ipv4-address", ipv4,
"ipv4-netmask", ipv4_netmask,
"ipv4-gateway", ipv4_gw,
@@ -583,6 +577,18 @@ bbl_ctrl_session_info(int fd, bbl_ctx_s *ctx, uint32_t session_id, json_t* argum
"ipv6-delegated-prefix", ipv6pd,
"ipv6-dns1", ipv6_dns1,
"ipv6-dns2", ipv6_dns2,
"dhcp-state", dhcp_state_string(session->dhcp_state),
"dhcp-server", format_ipv4_address(&session->dhcp_server_identifier),
"dhcp-lease-time", session->dhcp_lease_time,
"dhcp-lease-expire", lease_expire,
"dhcp-lease-expire-t1", lease_expire_t1,
"dhcp-lease-expire-t2", lease_expire_t2,
"dhcp-tx-discover", session->stats.dhcp_tx_discover,
"dhcp-tx-request", session->stats.dhcp_tx_request,
"dhcp-tx-release", session->stats.dhcp_tx_release,
"dhcp-rx-offer", session->stats.dhcp_rx_offer,
"dhcp-rx-ack", session->stats.dhcp_rx_ack,
"dhcp-rx-nak", session->stats.dhcp_rx_nak,
"dhcpv6-dns1", dhcpv6_dns1,
"dhcpv6-dns2", dhcpv6_dns2,
"tx-packets", session->stats.packets_tx,
+29 -5
View File
@@ -38,7 +38,9 @@ bbl_dhcp_restart(bbl_session_s *session) {
session->dhcp_lease_time = 0;
session->dhcp_t1 = 0;
session->dhcp_t2 = 0;
session->dhcp_server = 0;
session->dhcp_server_identifier = 0;
memset(&session->dhcp_server_mac, 0xff, ETH_ADDR_LEN); // init with broadcast MAC
session->dhcp_lease_timestamp.tv_sec = 0;
session->dhcp_lease_timestamp.tv_nsec = 0;
session->dhcp_request_timestamp.tv_sec = 0;
@@ -51,7 +53,7 @@ bbl_dhcp_restart(bbl_session_s *session) {
free(session->dhcp_domain_name);
session->dhcp_domain_name = NULL;
}
session->send_requests |= BBL_SEND_DHCPREQUEST;
session->send_requests |= BBL_SEND_DHCP_REQUEST;
bbl_session_tx_qnode_insert(session);
/* Reset session IP configuration */
@@ -82,7 +84,7 @@ bbl_dhcp_t1(timer_s *timer) {
session->dhcp_request_timestamp.tv_sec = 0;
session->dhcp_request_timestamp.tv_nsec = 0;
session->dhcp_state = BBL_DHCP_RENEWING;
session->send_requests = BBL_SEND_DHCPREQUEST;
session->send_requests = BBL_SEND_DHCP_REQUEST;
bbl_session_tx_qnode_insert(session);
}
}
@@ -113,21 +115,41 @@ bbl_dhcp_rx(bbl_ethernet_header_t *eth, bbl_dhcp_t *dhcp, bbl_session_s *session
return;
}
switch(dhcp->type) {
case DHCP_MESSAGE_OFFER:
session->stats.dhcp_rx_offer++;
LOG(DHCP, "DHCP (ID: %u) DHCP-Offer received\n", session->session_id);
break;
case DHCP_MESSAGE_ACK:
session->stats.dhcp_rx_ack++;
LOG(DHCP, "DHCP (ID: %u) DHCP-ACK received\n", session->session_id);
break;
case DHCP_MESSAGE_NAK:
session->stats.dhcp_rx_nak++;
LOG(DHCP, "DHCP (ID: %u) DHCP-NAK received\n", session->session_id);
break;
default:
/* Not expected ... */
return;
}
switch(session->dhcp_state) {
case BBL_DHCP_SELECTING:
if(dhcp->type == DHCP_MESSAGE_OFFER) {
session->dhcp_state = BBL_DHCP_REQUESTING;
session->dhcp_address = dhcp->header->yiaddr;
session->dhcp_server = dhcp->header->siaddr;
session->dhcp_server_identifier = dhcp->server_identifier;
memcpy(session->dhcp_server_mac, eth->src, ETH_ADDR_LEN);
session->dhcp_lease_time = dhcp->lease_time;
session->dhcp_lease_timestamp.tv_sec = eth->timestamp.tv_sec;
session->dhcp_lease_timestamp.tv_nsec = eth->timestamp.tv_nsec;
if(!(session->dhcp_address && session->dhcp_server_identifier && session->dhcp_lease_time)) {
LOG(ERROR, "DHCP (ID: %u) Invalid DHCP-OFFER!\n", session->session_id);
LOG(ERROR, "DHCP (ID: %u) Invalid DHCP-Offer!\n", session->session_id);
return bbl_dhcp_restart(session);
}
timer_add(&ctx->timer_root, &session->timer_dhcp_t2, "DHCP T2", session->dhcp_lease_time, 0, session, &bbl_dhcp_t2);
session->send_requests |= BBL_SEND_DHCPREQUEST;
session->send_requests |= BBL_SEND_DHCP_REQUEST;
bbl_session_tx_qnode_insert(session);
}
break;
@@ -135,6 +157,7 @@ bbl_dhcp_rx(bbl_ethernet_header_t *eth, bbl_dhcp_t *dhcp, bbl_session_s *session
if(dhcp->type == DHCP_MESSAGE_ACK) {
session->dhcp_state = BBL_DHCP_BOUND;
session->dhcp_address = dhcp->header->yiaddr;
session->dhcp_server = dhcp->header->siaddr;
session->dhcp_server_identifier = dhcp->server_identifier;
session->dhcp_lease_time = dhcp->lease_time;
session->dhcp_lease_timestamp.tv_sec = eth->timestamp.tv_sec;
@@ -193,12 +216,13 @@ bbl_dhcp_rx(bbl_ethernet_header_t *eth, bbl_dhcp_t *dhcp, bbl_session_s *session
if(dhcp->type == DHCP_MESSAGE_ACK) {
session->dhcp_state = BBL_DHCP_BOUND;
session->dhcp_address = dhcp->header->yiaddr;
session->dhcp_server = dhcp->header->siaddr;
session->dhcp_server_identifier = dhcp->server_identifier;
session->dhcp_lease_time = dhcp->lease_time;
session->dhcp_lease_timestamp.tv_sec = eth->timestamp.tv_sec;
session->dhcp_lease_timestamp.tv_nsec = eth->timestamp.tv_nsec;
if(!(session->dhcp_address && session->dhcp_server_identifier && session->dhcp_lease_time)) {
LOG(ERROR, "DHCP (ID: %u) Restart because of invalid DHCP-ACK!\n", session->session_id);
LOG(ERROR, "DHCP (ID: %u) Invalid DHCP-ACK!\n", session->session_id);
return bbl_dhcp_restart(session);
}
session->dhcp_t1 = 0.5 * session->dhcp_lease_time; if(!session->dhcp_t1) session->dhcp_t1 = 1;
+12 -1
View File
@@ -273,7 +273,17 @@ bbl_session_clear(bbl_ctx_s *ctx, bbl_session_s *session)
break;
}
} else {
bbl_session_update_state(ctx, session, BBL_TERMINATED);
if(session->dhcp_state > BBL_DHCP_SELECTING) {
bbl_session_update_state(ctx, session, BBL_TERMINATING);
session->dhcp_state = BBL_DHCP_RELEASE;
session->dhcp_xid = rand();
session->dhcp_request_timestamp.tv_sec = 0;
session->dhcp_request_timestamp.tv_nsec = 0;
session->send_requests |= BBL_SEND_DHCP_REQUEST;
bbl_session_tx_qnode_insert(session);
} else {
bbl_session_update_state(ctx, session, BBL_TERMINATED);
}
}
}
@@ -360,6 +370,7 @@ bbl_sessions_init(bbl_ctx_s *ctx)
return false;
}
memset(&session->server_mac, 0xff, ETH_ADDR_LEN); // init with broadcast MAC
memset(&session->dhcp_server_mac, 0xff, ETH_ADDR_LEN); // init with broadcast MAC
session->session_id = i; // BNG Blaster internal session identifier
session->access_type = access_config->access_type;
session->vlan_key.ifindex = access_config->access_if->ifindex;
+28 -11
View File
@@ -1201,7 +1201,7 @@ bbl_dhcp_timeout (timer_s *timer)
return;
}
session->send_requests = BBL_SEND_DHCPREQUEST;
session->send_requests = BBL_SEND_DHCP_REQUEST;
bbl_session_tx_qnode_insert(session);
}
@@ -1228,19 +1228,20 @@ bbl_encode_packet_dhcp (bbl_session_s *session) {
dhcp.header = &header;
eth.dst = session->dhcp_server_mac;
eth.src = session->client_mac;
eth.dst = (uint8_t*)broadcast_mac;
eth.vlan_outer = session->vlan_key.outer_vlan_id;
eth.vlan_inner = session->vlan_key.inner_vlan_id;
eth.vlan_three = session->access_third_vlan;
eth.vlan_outer_priority = ctx->config.pppoe_vlan_priority;
eth.vlan_outer_priority = ctx->config.dhcp_vlan_priority;
eth.vlan_inner_priority = eth.vlan_outer_priority;
eth.type = ETH_TYPE_IPV4;
eth.next = &ipv4;
ipv4.src = session->ip_address;
ipv4.dst = IPV4_BROADCAST;
ipv4.dst = session->dhcp_server;
ipv4.ttl = 255;
ipv4.tos = ctx->config.dhcp_tos;
ipv4.protocol = PROTOCOL_IPV4_UDP;
ipv4.next = &udp;
udp.src = DHCP_UDP_CLIENT;
@@ -1253,8 +1254,10 @@ bbl_encode_packet_dhcp (bbl_session_s *session) {
header.htype = 1; /* fixed set to ethernet */
header.hlen = 6;
header.xid = session->dhcp_xid;
if(ctx->config.dhcp_broadcast) {
if(ctx->config.dhcp_broadcast && session->dhcp_state != BBL_DHCP_RELEASE) {
header.flags = htobe16(1 << 15);
eth.dst = (uint8_t*)broadcast_mac;
ipv4.dst = IPV4_BROADCAST;
}
header.ciaddr = session->ip_address;
memcpy(header.chaddr, session->client_mac, ETH_ADDR_LEN);
@@ -1270,7 +1273,7 @@ bbl_encode_packet_dhcp (bbl_session_s *session) {
}
/* Option 82 ... */
if(session->agent_circuit_id || session->agent_remote_id) {
if((session->agent_circuit_id || session->agent_remote_id) && session->dhcp_state != BBL_DHCP_RELEASE) {
access_line.aci = session->agent_circuit_id;
access_line.ari = session->agent_remote_id;
dhcp.access_line = &access_line;
@@ -1279,6 +1282,10 @@ bbl_encode_packet_dhcp (bbl_session_s *session) {
switch(session->dhcp_state) {
case BBL_DHCP_SELECTING:
dhcp.type = DHCP_MESSAGE_DISCOVER;
session->stats.dhcp_tx_discover++;
LOG(DHCP, "DHCP (ID: %u) DHCP-Discover send\n", session->session_id);
eth.dst = (uint8_t*)broadcast_mac;
ipv4.dst = IPV4_BROADCAST;
dhcp.parameter_request_list = true;
dhcp.option_netmask = true;
dhcp.option_dns1 = true;
@@ -1293,6 +1300,8 @@ bbl_encode_packet_dhcp (bbl_session_s *session) {
break;
case BBL_DHCP_REQUESTING:
dhcp.type = DHCP_MESSAGE_REQUEST;
session->stats.dhcp_tx_request++;
LOG(DHCP, "DHCP (ID: %u) DHCP-Request send\n", session->session_id);
dhcp.option_address = true;
dhcp.address = session->dhcp_address;
dhcp.option_server_identifier = true;
@@ -1307,16 +1316,24 @@ bbl_encode_packet_dhcp (bbl_session_s *session) {
break;
case BBL_DHCP_RENEWING:
dhcp.type = DHCP_MESSAGE_REQUEST;
session->stats.dhcp_tx_request++;
LOG(DHCP, "DHCP (ID: %u) DHCP-Request send\n", session->session_id);
break;
case BBL_DHCP_DHCPRELEASE:
case BBL_DHCP_RELEASE:
dhcp.type = DHCP_MESSAGE_RELEASE;
header.flags = 0;
session->stats.dhcp_tx_release++;
LOG(DHCP, "DHCP (ID: %u) DHCP-Release send\n", session->session_id);
dhcp.option_server_identifier = true;
dhcp.server_identifier = session->dhcp_server_identifier;
if(session->session_state == BBL_TERMINATING) {
bbl_session_update_state(ctx, session, BBL_TERMINATED);
}
break;
default:
return IGNORED;
}
timer_add(&ctx->timer_root, &session->timer_dhcp_retry, "DHCP timeout", 5, 0, session, &bbl_dhcp_timeout);
timer_add(&ctx->timer_root, &session->timer_dhcp_retry, "DHCP timeout", ctx->config.dhcp_timeout, 0, session, &bbl_dhcp_timeout);
interface->stats.dhcp_tx++;
return encode_ethernet(session->write_buf, &session->write_idx, &eth);
@@ -1456,9 +1473,9 @@ bbl_encode_packet (bbl_session_s *session, uint8_t *buf, uint16_t *len, bool *ac
} else if (session->send_requests & BBL_SEND_ARP_REPLY) {
result = bbl_encode_packet_arp_reply(session);
session->send_requests &= ~BBL_SEND_ARP_REPLY;
} else if (session->send_requests & BBL_SEND_DHCPREQUEST) {
} else if (session->send_requests & BBL_SEND_DHCP_REQUEST) {
result = bbl_encode_packet_dhcp(session);
session->send_requests &= ~BBL_SEND_DHCPREQUEST;
session->send_requests &= ~BBL_SEND_DHCP_REQUEST;
} else {
session->send_requests = 0;
}