+odp_set_nd(struct dp_packet *packet, const struct ovs_key_nd *key,
+ const struct ovs_key_nd *mask)
+{
+ const struct ovs_nd_msg *ns = dp_packet_l4(packet);
+ const struct ovs_nd_opt *nd_opt = dp_packet_get_nd_payload(packet);
+
+ if (OVS_LIKELY(ns && nd_opt)) {
+ int bytes_remain = dp_packet_l4_size(packet) - sizeof(*ns);
+ ovs_be32 tgt_buf[4];
+ struct eth_addr sll_buf = eth_addr_zero;
+ struct eth_addr tll_buf = eth_addr_zero;
+
+ while (bytes_remain >= ND_OPT_LEN && nd_opt->nd_opt_len != 0) {
+ if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR
+ && nd_opt->nd_opt_len == 1) {
+ sll_buf = nd_opt->nd_opt_mac;
+ ether_addr_copy_masked(&sll_buf, key->nd_sll, mask->nd_sll);
+
+ /* A packet can only contain one SLL or TLL option */
+ break;
+ } else if (nd_opt->nd_opt_type == ND_OPT_TARGET_LINKADDR
+ && nd_opt->nd_opt_len == 1) {
+ tll_buf = nd_opt->nd_opt_mac;
+ ether_addr_copy_masked(&tll_buf, key->nd_tll, mask->nd_tll);
+
+ /* A packet can only contain one SLL or TLL option */
+ break;
+ }
+
+ nd_opt += nd_opt->nd_opt_len;
+ bytes_remain -= nd_opt->nd_opt_len * ND_OPT_LEN;
+ }
+
+ packet_set_nd(packet,
+ mask_ipv6_addr(ns->target.be32,
+ key->nd_target, mask->nd_target, tgt_buf),
+ sll_buf,
+ tll_buf);
+ }
+}
+
+static void
+odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a)