- h0 = vlib_buffer_get_current (b0);
-
- /*
- * udp_local hands us the DHCPV6 header.
- */
- u0 = (void *)h0 -(sizeof(*u0));
- ip0 = (void *)u0 -(sizeof(*ip0));
- e_h0 = (void *)ip0 - ethernet_buffer_header_size(b0);
-
- clib_memcpy(client_src_mac, e_h0->src_address, 6);
-
- switch (h0->u.msg_type) {
- case DHCPV6_MSG_SOLICIT:
- case DHCPV6_MSG_REQUEST:
- case DHCPV6_MSG_CONFIRM:
- case DHCPV6_MSG_RENEW:
- case DHCPV6_MSG_REBIND:
- case DHCPV6_MSG_RELEASE:
- case DHCPV6_MSG_DECLINE:
- case DHCPV6_MSG_INFORMATION_REQUEST:
- case DHCPV6_MSG_RELAY_FORW:
- /* send to server */
- break;
- case DHCPV6_MSG_RELAY_REPL:
- /* send to client */
- next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT;
- error0 = 0;
- pkts_to_client++;
- goto do_enqueue;
- default:
- /* drop the packet */
- pkts_wrong_msg_type++;
- error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE;
- next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
- goto do_trace;
-
- }
-
- /* Send to DHCPV6 server via the configured FIB */
- rx_sw_if_index = sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
- rx_fib_idx = im->mfib_index_by_sw_if_index [rx_sw_if_index];
- proxy = dhcp_get_proxy(dpm, rx_fib_idx, FIB_PROTOCOL_IP6);
-
- if (PREDICT_FALSE (NULL == proxy))
- {
- error0 = DHCPV6_PROXY_ERROR_NO_SERVER;
- next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
- pkts_no_server++;
- goto do_trace;
- }
-
- server = &proxy->dhcp_servers[0];
- server_fib_idx = server->server_fib_index;
- vnet_buffer(b0)->sw_if_index[VLIB_TX] = server_fib_idx;
-
-
- /* relay-option header pointer */
- vlib_buffer_advance(b0, -(sizeof(*fwd_opt)));
- fwd_opt = vlib_buffer_get_current(b0);
- /* relay message header pointer */
- vlib_buffer_advance(b0, -(sizeof(*r1)));
- r1 = vlib_buffer_get_current(b0);
-
- vlib_buffer_advance(b0, -(sizeof(*u1)));
- u1 = vlib_buffer_get_current(b0);
-
- vlib_buffer_advance(b0, -(sizeof(*ip1)));
- ip1 = vlib_buffer_get_current(b0);
-
- /* fill in all that rubbish... */
- len = clib_net_to_host_u16(u0->length) - sizeof(udp_header_t);
- copy_ip6_address(&r1->peer_addr, &ip0->src_address);
-
- r1->msg_type = DHCPV6_MSG_RELAY_FORW;
- fwd_opt->length = clib_host_to_net_u16(len);
- fwd_opt->option = clib_host_to_net_u16(DHCPV6_OPTION_RELAY_MSG);
-
- r1->hop_count++;
- r1->hop_count = (h0->u.msg_type != DHCPV6_MSG_RELAY_FORW) ? 0 : r1->hop_count;
-
- if (PREDICT_FALSE(r1->hop_count >= HOP_COUNT_LIMIT))
- {
- error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS;
- next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
- pkts_no_exceeding_max_hop++;
- goto do_trace;
- }
-
-
- /* If relay-fwd and src address is site or global unicast address */
- if (h0->u.msg_type == DHCPV6_MSG_RELAY_FORW &&
- ((ip0->src_address.as_u8[0] & 0xe0) == 0x20 ||
- (ip0->src_address.as_u8[0] & 0xfe) == 0xfc))
- {
- /* Set link address to zero */
- r1->link_addr.as_u64[0] = 0;
- r1->link_addr.as_u64[1] = 0;
- goto link_address_set;
- }
-
- /* if receiving interface is unnumbered, use receiving interface
- * IP address as link address, otherwise use the loopback interface
- * IP address as link address.
- */
-
- swif = vnet_get_sw_interface (vnm, rx_sw_if_index);
- if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
- sw_if_index = swif->unnumbered_sw_if_index;
-
- ia0 = ip6_interface_first_global_or_site_address(&ip6_main, sw_if_index);
- if (ia0 == 0)
- {
- error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS;
- next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
- pkts_no_interface_address++;
- goto do_trace;
- }
-
- copy_ip6_address(&r1->link_addr, ia0);
-
- link_address_set:
- fl = vlib_buffer_get_free_list (vm, vlib_buffer_get_free_list_index (b0));
-
- if ((b0->current_length+sizeof(*id1)+sizeof(*vss1)+sizeof(*cmac))
- > fl->n_data_bytes)
- {
- error0 = DHCPV6_PROXY_ERROR_PKT_TOO_BIG;
- next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
- pkts_too_big++;
- goto do_trace;
- }
-
- id1 = (dhcpv6_int_id_t *) (((uword) ip1) + b0->current_length);
- b0->current_length += (sizeof (*id1));
-
- id1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_INTERFACE_ID);
- id1->opt.length = clib_host_to_net_u16(sizeof(rx_sw_if_index));
- id1->int_idx = clib_host_to_net_u32(rx_sw_if_index);
-
- u1->length =0;
- if (h0->u.msg_type != DHCPV6_MSG_RELAY_FORW)
- {
- cmac = (dhcpv6_client_mac_t *) (((uword) ip1) + b0->current_length);
- b0->current_length += (sizeof (*cmac));
- cmac->opt.length =clib_host_to_net_u16(sizeof(*cmac) -
- sizeof(cmac->opt));
- cmac->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS);
- cmac->link_type = clib_host_to_net_u16(1); // ethernet
- clib_memcpy(cmac->data, client_src_mac, 6);
- u1->length += sizeof(*cmac);
- }
-
- vss = dhcp_get_vss_info(dpm, rx_fib_idx, FIB_PROTOCOL_IP6);
-
- if (NULL != vss) {
- vss1 = (dhcpv6_vss_t *) (((uword) ip1) + b0->current_length);
- b0->current_length += (sizeof (*vss1));
- vss1->opt.length =clib_host_to_net_u16(sizeof(*vss1) -
- sizeof(vss1->opt));
- vss1->opt.option = clib_host_to_net_u16(DHCPV6_OPTION_VSS);
- vss1->data[0] = 1; // type
- vss1->data[1] = vss->oui >>16 & 0xff;
- vss1->data[2] = vss->oui >>8 & 0xff;
- vss1->data[3] = vss->oui & 0xff;
- vss1->data[4] = vss->fib_id >> 24 & 0xff;
- vss1->data[5] = vss->fib_id >> 16 & 0xff;
- vss1->data[6] = vss->fib_id >> 8 & 0xff;
- vss1->data[7] = vss->fib_id & 0xff;
- u1->length += sizeof(*vss1);
- }
-
- pkts_to_server++;
- u1->checksum = 0;
- u1->src_port = clib_host_to_net_u16(UDP_DST_PORT_dhcpv6_to_client);
- u1->dst_port = clib_host_to_net_u16(UDP_DST_PORT_dhcpv6_to_server);
-
- u1->length =
- clib_host_to_net_u16( clib_net_to_host_u16(fwd_opt->length) +
- sizeof(*r1) + sizeof(*fwd_opt) +
- sizeof(*u1) + sizeof(*id1) + u1->length);
-
- memset(ip1, 0, sizeof(*ip1));
- ip1->ip_version_traffic_class_and_flow_label = 0x60;
- ip1->payload_length = u1->length;
- ip1->protocol = PROTO_UDP;
- ip1->hop_limit = HOP_COUNT_LIMIT;
- src = ((server->dhcp_server.ip6.as_u64[0] ||
- server->dhcp_server.ip6.as_u64[1]) ?
- &server->dhcp_server.ip6 :
- &all_dhcpv6_server_address);
- copy_ip6_address(&ip1->dst_address, src);
-
-
- ia0 = ip6_interface_first_global_or_site_address
- (&ip6_main, vnet_buffer(b0)->sw_if_index[VLIB_RX]);
-
- src = (proxy->dhcp_src_address.ip6.as_u64[0] ||
- proxy->dhcp_src_address.ip6.as_u64[1]) ?
- &proxy->dhcp_src_address.ip6 : ia0;
- if (ia0 == 0)
- {
- error0 = DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS;
- next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
- pkts_no_src_address++;
- goto do_trace;
- }
+ h0 = vlib_buffer_get_current (b0);
+
+ /*
+ * udp_local hands us the DHCPV6 header.
+ */
+ u0 = (void *) h0 - (sizeof (*u0));
+ ip0 = (void *) u0 - (sizeof (*ip0));
+ e_h0 = (void *) ip0 - ethernet_buffer_header_size (b0);
+
+ clib_memcpy (client_src_mac, e_h0->src_address, 6);
+
+ switch (h0->msg_type)
+ {
+ case DHCPV6_MSG_SOLICIT:
+ case DHCPV6_MSG_REQUEST:
+ case DHCPV6_MSG_CONFIRM:
+ case DHCPV6_MSG_RENEW:
+ case DHCPV6_MSG_REBIND:
+ case DHCPV6_MSG_RELEASE:
+ case DHCPV6_MSG_DECLINE:
+ case DHCPV6_MSG_INFORMATION_REQUEST:
+ case DHCPV6_MSG_RELAY_FORW:
+ /* send to server */
+ break;
+ case DHCPV6_MSG_RELAY_REPL:
+ /* send to client */
+ next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT;
+ error0 = 0;
+ pkts_to_client++;
+ goto do_enqueue;
+ default:
+ /* drop the packet */
+ pkts_wrong_msg_type++;
+ error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE;
+ next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
+ goto do_trace;
+
+ }
+
+ /* Send to DHCPV6 server via the configured FIB */
+ rx_sw_if_index = sw_if_index =
+ vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ rx_fib_idx = im->mfib_index_by_sw_if_index[rx_sw_if_index];
+ proxy = dhcp_get_proxy (dpm, rx_fib_idx, FIB_PROTOCOL_IP6);
+
+ if (PREDICT_FALSE (NULL == proxy))
+ {
+ error0 = DHCPV6_PROXY_ERROR_NO_SERVER;
+ next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
+ pkts_no_server++;
+ goto do_trace;
+ }
+
+ server = &proxy->dhcp_servers[0];
+ server_fib_idx = server->server_fib_index;
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = server_fib_idx;
+
+
+ /* relay-option header pointer */
+ vlib_buffer_advance (b0, -(sizeof (*fwd_opt)));
+ fwd_opt = vlib_buffer_get_current (b0);
+ /* relay message header pointer */
+ vlib_buffer_advance (b0, -(sizeof (*r1)));
+ r1 = vlib_buffer_get_current (b0);
+
+ vlib_buffer_advance (b0, -(sizeof (*u1)));
+ u1 = vlib_buffer_get_current (b0);
+
+ vlib_buffer_advance (b0, -(sizeof (*ip1)));
+ ip1 = vlib_buffer_get_current (b0);
+
+ /* fill in all that rubbish... */
+ len = clib_net_to_host_u16 (u0->length) - sizeof (udp_header_t);
+ copy_ip6_address (&r1->peer_addr, &ip0->src_address);
+
+ r1->msg_type = DHCPV6_MSG_RELAY_FORW;
+ fwd_opt->length = clib_host_to_net_u16 (len);
+ fwd_opt->option = clib_host_to_net_u16 (DHCPV6_OPTION_RELAY_MSG);
+
+ r1->hop_count++;
+ r1->hop_count =
+ (h0->msg_type != DHCPV6_MSG_RELAY_FORW) ? 0 : r1->hop_count;
+
+ if (PREDICT_FALSE (r1->hop_count >= HOP_COUNT_LIMIT))
+ {
+ error0 = DHCPV6_RELAY_PKT_DROP_MAX_HOPS;
+ next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
+ pkts_no_exceeding_max_hop++;
+ goto do_trace;
+ }
+
+
+ /* If relay-fwd and src address is site or global unicast address */
+ if (h0->msg_type == DHCPV6_MSG_RELAY_FORW &&
+ ((ip0->src_address.as_u8[0] & 0xe0) == 0x20 ||
+ (ip0->src_address.as_u8[0] & 0xfe) == 0xfc))
+ {
+ /* Set link address to zero */
+ r1->link_addr.as_u64[0] = 0;
+ r1->link_addr.as_u64[1] = 0;
+ goto link_address_set;
+ }
+
+ /* if receiving interface is unnumbered, use receiving interface
+ * IP address as link address, otherwise use the loopback interface
+ * IP address as link address.
+ */
+
+ swif = vnet_get_sw_interface (vnm, rx_sw_if_index);
+ if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
+ sw_if_index = swif->unnumbered_sw_if_index;
+
+ ia0 =
+ ip6_interface_first_global_or_site_address (&ip6_main,
+ sw_if_index);
+ if (ia0 == 0)
+ {
+ error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS;
+ next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
+ pkts_no_interface_address++;
+ goto do_trace;
+ }
+
+ copy_ip6_address (&r1->link_addr, ia0);
+
+ link_address_set:
+ fl =
+ vlib_buffer_get_free_list (vm,
+ vlib_buffer_get_free_list_index (b0));
+
+ if ((b0->current_length + sizeof (*id1) + sizeof (*vss1) +
+ sizeof (*cmac)) > fl->n_data_bytes)
+ {
+ error0 = DHCPV6_PROXY_ERROR_PKT_TOO_BIG;
+ next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
+ pkts_too_big++;
+ goto do_trace;
+ }
+
+ id1 = (dhcpv6_int_id_t *) (((uword) ip1) + b0->current_length);
+ b0->current_length += (sizeof (*id1));
+
+ id1->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_INTERFACE_ID);
+ id1->opt.length = clib_host_to_net_u16 (sizeof (rx_sw_if_index));
+ id1->int_idx = clib_host_to_net_u32 (rx_sw_if_index);
+
+ u1->length = 0;
+ if (h0->msg_type != DHCPV6_MSG_RELAY_FORW)
+ {
+ cmac =
+ (dhcpv6_client_mac_t *) (((uword) ip1) + b0->current_length);
+ b0->current_length += (sizeof (*cmac));
+ cmac->opt.length = clib_host_to_net_u16 (sizeof (*cmac) -
+ sizeof (cmac->opt));
+ cmac->opt.option =
+ clib_host_to_net_u16
+ (DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS);
+ cmac->link_type = clib_host_to_net_u16 (1); /* ethernet */
+ clib_memcpy (cmac->data, client_src_mac, 6);
+ u1->length += sizeof (*cmac);
+ }
+
+ vss = dhcp_get_vss_info (dpm, rx_fib_idx, FIB_PROTOCOL_IP6);
+
+ if (vss)
+ {
+ u16 id_len; /* length of VPN ID */
+ u16 type_len = sizeof (vss1->vss_type);
+
+ vss1 = (dhcpv6_vss_t *) (((uword) ip1) + b0->current_length);
+ vss1->vss_type = vss->vss_type;
+ if (vss->vss_type == VSS_TYPE_VPN_ID)
+ {
+ id_len = sizeof (vss->vpn_id); /* vpn_id is 7 bytes */
+ memcpy (vss1->data, vss->vpn_id, id_len);
+ }
+ else if (vss->vss_type == VSS_TYPE_ASCII)
+ {
+ id_len = vec_len (vss->vpn_ascii_id);
+ memcpy (vss1->data, vss->vpn_ascii_id, id_len);
+ }
+ else /* must be VSS_TYPE_DEFAULT, no VPN ID */
+ id_len = 0;
+
+ vss1->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_VSS);
+ vss1->opt.length = clib_host_to_net_u16 (type_len + id_len);
+ u1->length += type_len + id_len + sizeof (vss1->opt);
+ b0->current_length += type_len + id_len + sizeof (vss1->opt);
+ }
+
+ pkts_to_server++;
+ u1->checksum = 0;
+ u1->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcpv6_to_client);
+ u1->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcpv6_to_server);
+
+ u1->length =
+ clib_host_to_net_u16 (clib_net_to_host_u16 (fwd_opt->length) +
+ sizeof (*r1) + sizeof (*fwd_opt) +
+ sizeof (*u1) + sizeof (*id1) + u1->length);
+
+ clib_memset (ip1, 0, sizeof (*ip1));
+ ip1->ip_version_traffic_class_and_flow_label = 0x60;
+ ip1->payload_length = u1->length;
+ ip1->protocol = PROTO_UDP;
+ ip1->hop_limit = HOP_COUNT_LIMIT;
+ src = ((server->dhcp_server.ip6.as_u64[0] ||
+ server->dhcp_server.ip6.as_u64[1]) ?
+ &server->dhcp_server.ip6 : &all_dhcpv6_server_address);
+ copy_ip6_address (&ip1->dst_address, src);
+
+
+ ia0 = ip6_interface_first_global_or_site_address
+ (&ip6_main, vnet_buffer (b0)->sw_if_index[VLIB_RX]);
+
+ src = (proxy->dhcp_src_address.ip6.as_u64[0] ||
+ proxy->dhcp_src_address.ip6.as_u64[1]) ?
+ &proxy->dhcp_src_address.ip6 : ia0;
+ if (ia0 == 0)
+ {
+ error0 = DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS;
+ next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
+ pkts_no_src_address++;
+ goto do_trace;
+ }