static void odp_execute_sample(void *dp, struct dpif_packet *packet, bool steal, struct pkt_metadata *md, const struct nlattr *action, odp_execute_cb dp_execute_action, bool more_actions) { const struct nlattr *subactions = NULL; const struct nlattr *a; size_t left; NL_NESTED_FOR_EACH_UNSAFE (a, left, action) { int type = nl_attr_type(a); switch ((enum ovs_sample_attr) type) { case OVS_SAMPLE_ATTR_PROBABILITY: if (random_uint32() >= nl_attr_get_u32(a)) { return; } break; case OVS_SAMPLE_ATTR_ACTIONS: subactions = a; break; case OVS_SAMPLE_ATTR_UNSPEC: case __OVS_SAMPLE_ATTR_MAX: default: OVS_NOT_REACHED(); } }
static int lookup_brc_multicast_group(int *multicast_group) { struct nl_sock *sock; struct ofpbuf request, *reply; struct nlattr *attrs[ARRAY_SIZE(brc_multicast_policy)]; int retval; retval = nl_sock_create(NETLINK_GENERIC, &sock); if (retval) { return retval; } ofpbuf_init(&request, 0); nl_msg_put_genlmsghdr(&request, 0, brc_family, NLM_F_REQUEST, BRC_GENL_C_QUERY_MC, 1); retval = nl_sock_transact(sock, &request, &reply); ofpbuf_uninit(&request); if (retval) { nl_sock_destroy(sock); return retval; } if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN, brc_multicast_policy, attrs, ARRAY_SIZE(brc_multicast_policy))) { nl_sock_destroy(sock); ofpbuf_delete(reply); return EPROTO; } *multicast_group = nl_attr_get_u32(attrs[BRC_GENL_A_MC_GROUP]); nl_sock_destroy(sock); ofpbuf_delete(reply); return 0; }
/* Looks up the Netlink multicast group and datapath index of a datapath * by either the datapath index or name. If 'dp_idx' points to a value * of '-1', then 'dp_name' is used to lookup the datapath. If successful, * stores the multicast group in '*multicast_group' and the index in * '*dp_idx' and returns 0. Otherwise, returns a positive errno value. */ static int query_datapath(int *dp_idx, int *multicast_group, const char *dp_name) { struct nl_sock *sock; struct ofpbuf request, *reply; struct nlattr *attrs[ARRAY_SIZE(openflow_multicast_policy)]; int retval; retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &sock); if (retval) { return retval; } ofpbuf_init(&request, 0); nl_msg_put_genlmsghdr(&request, sock, 0, openflow_family, NLM_F_REQUEST, DP_GENL_C_QUERY_DP, 1); if (*dp_idx != -1) { nl_msg_put_u32(&request, DP_GENL_A_DP_IDX, *dp_idx); } if (dp_name) { nl_msg_put_string(&request, DP_GENL_A_DP_NAME, dp_name); } retval = nl_sock_transact(sock, &request, &reply); ofpbuf_uninit(&request); if (retval) { nl_sock_destroy(sock); return retval; } if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN, openflow_multicast_policy, attrs, ARRAY_SIZE(openflow_multicast_policy))) { nl_sock_destroy(sock); ofpbuf_delete(reply); return EPROTO; } *dp_idx = nl_attr_get_u32(attrs[DP_GENL_A_DP_IDX]); *multicast_group = nl_attr_get_u32(attrs[DP_GENL_A_MC_GROUP]); nl_sock_destroy(sock); ofpbuf_delete(reply); return 0; }
/* Tries to receive an openflow message from datapath 'dp_idx' on 'sock'. If * successful, stores the received message into '*msgp' and returns 0. The * caller is responsible for destroying the message with ofpbuf_delete(). On * failure, returns a positive errno value and stores a null pointer into * '*msgp'. * * Only Netlink messages with embedded OpenFlow messages are accepted. Other * Netlink messages provoke errors. * * If 'wait' is true, dpif_recv_openflow waits for a message to be ready; * otherwise, returns EAGAIN if the 'sock' receive buffer is empty. */ int dpif_recv_openflow(struct dpif *dp, int dp_idx, struct ofpbuf **bufferp, bool wait) { struct nlattr *attrs[ARRAY_SIZE(openflow_policy)]; struct ofpbuf *buffer; struct ofp_header *oh; uint16_t ofp_len; buffer = *bufferp = NULL; do { int retval; do { ofpbuf_delete(buffer); retval = nl_sock_recv(dp->sock, &buffer, wait); } while (retval == ENOBUFS || (!retval && (nl_msg_nlmsghdr(buffer)->nlmsg_type == NLMSG_DONE || nl_msg_nlmsgerr(buffer, NULL)))); if (retval) { if (retval != EAGAIN) { VLOG_WARN_RL(&rl, "dpif_recv_openflow: %s", strerror(retval)); } return retval; } if (nl_msg_genlmsghdr(buffer) == NULL) { VLOG_DBG_RL(&rl, "received packet too short for Generic Netlink"); goto error; } if (nl_msg_nlmsghdr(buffer)->nlmsg_type != openflow_family) { VLOG_DBG_RL(&rl, "received type (%"PRIu16") != openflow family (%d)", nl_msg_nlmsghdr(buffer)->nlmsg_type, openflow_family); goto error; } if (!nl_policy_parse(buffer, NLMSG_HDRLEN + GENL_HDRLEN, openflow_policy, attrs, ARRAY_SIZE(openflow_policy))) { goto error; } } while (nl_attr_get_u32(attrs[DP_GENL_A_DP_IDX]) != dp_idx); oh = buffer->data = (void *) nl_attr_get(attrs[DP_GENL_A_OPENFLOW]); buffer->size = nl_attr_get_size(attrs[DP_GENL_A_OPENFLOW]); ofp_len = ntohs(oh->length); if (ofp_len != buffer->size) { VLOG_WARN_RL(&rl, "ofp_header.length %"PRIu16" != attribute length %zu\n", ofp_len, buffer->size); buffer->size = MIN(ofp_len, buffer->size); } *bufferp = buffer; return 0; error: ofpbuf_delete(buffer); return EPROTO; }
static void odp_execute_set_action(struct dpif_packet *packet, const struct nlattr *a, struct pkt_metadata *md) { enum ovs_key_attr type = nl_attr_type(a); const struct ovs_key_ipv4 *ipv4_key; const struct ovs_key_ipv6 *ipv6_key; const struct ovs_key_tcp *tcp_key; const struct ovs_key_udp *udp_key; const struct ovs_key_sctp *sctp_key; switch (type) { case OVS_KEY_ATTR_PRIORITY: md->skb_priority = nl_attr_get_u32(a); break; case OVS_KEY_ATTR_TUNNEL: odp_set_tunnel_action(a, &md->tunnel); break; case OVS_KEY_ATTR_SKB_MARK: md->pkt_mark = nl_attr_get_u32(a); break; case OVS_KEY_ATTR_ETHERNET: odp_eth_set_addrs(&packet->ofpbuf, nl_attr_get_unspec(a, sizeof(struct ovs_key_ethernet))); break; case OVS_KEY_ATTR_IPV4: ipv4_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv4)); packet_set_ipv4(&packet->ofpbuf, ipv4_key->ipv4_src, ipv4_key->ipv4_dst, ipv4_key->ipv4_tos, ipv4_key->ipv4_ttl); break; case OVS_KEY_ATTR_IPV6: ipv6_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv6)); packet_set_ipv6(&packet->ofpbuf, ipv6_key->ipv6_proto, ipv6_key->ipv6_src, ipv6_key->ipv6_dst, ipv6_key->ipv6_tclass, ipv6_key->ipv6_label, ipv6_key->ipv6_hlimit); break; case OVS_KEY_ATTR_TCP: tcp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_tcp)); packet_set_tcp_port(&packet->ofpbuf, tcp_key->tcp_src, tcp_key->tcp_dst); break; case OVS_KEY_ATTR_UDP: udp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_udp)); packet_set_udp_port(&packet->ofpbuf, udp_key->udp_src, udp_key->udp_dst); break; case OVS_KEY_ATTR_SCTP: sctp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_sctp)); packet_set_sctp_port(&packet->ofpbuf, sctp_key->sctp_src, sctp_key->sctp_dst); break; case OVS_KEY_ATTR_MPLS: set_mpls_lse(&packet->ofpbuf, nl_attr_get_be32(a)); break; case OVS_KEY_ATTR_ARP: set_arp(&packet->ofpbuf, nl_attr_get_unspec(a, sizeof(struct ovs_key_arp))); break; case OVS_KEY_ATTR_DP_HASH: packet->dp_hash = md->dp_hash = nl_attr_get_u32(a); break; case OVS_KEY_ATTR_RECIRC_ID: md->recirc_id = nl_attr_get_u32(a); break; case OVS_KEY_ATTR_UNSPEC: case OVS_KEY_ATTR_ENCAP: case OVS_KEY_ATTR_ETHERTYPE: case OVS_KEY_ATTR_IN_PORT: case OVS_KEY_ATTR_VLAN: case OVS_KEY_ATTR_ICMP: case OVS_KEY_ATTR_ICMPV6: case OVS_KEY_ATTR_ND: case OVS_KEY_ATTR_TCP_FLAGS: case __OVS_KEY_ATTR_MAX: default: OVS_NOT_REACHED(); } }
void format_odp_action(struct ds *ds, const struct nlattr *a) { const uint8_t *eth; ovs_be32 ip; if (nl_attr_get_size(a) != odp_action_len(nl_attr_type(a))) { ds_put_format(ds, "bad length %zu, expected %d for: ", nl_attr_get_size(a), odp_action_len(nl_attr_type(a))); format_generic_odp_action(ds, a); return; } switch (nl_attr_type(a)) { case OVS_ACTION_ATTR_OUTPUT: ds_put_format(ds, "%"PRIu16, nl_attr_get_u32(a)); break; case OVS_ACTION_ATTR_USERSPACE: ds_put_format(ds, "userspace(%"PRIu64")", nl_attr_get_u64(a)); break; case OVS_ACTION_ATTR_SET_TUNNEL: ds_put_format(ds, "set_tunnel(%#"PRIx64")", ntohll(nl_attr_get_be64(a))); break; case OVS_ACTION_ATTR_PUSH_VLAN: ds_put_format(ds, "push_vlan(vid=%"PRIu16",pcp=%d)", vlan_tci_to_vid(nl_attr_get_be16(a)), vlan_tci_to_pcp(nl_attr_get_be16(a))); break; case OVS_ACTION_ATTR_POP_VLAN: ds_put_format(ds, "pop_vlan"); break; case OVS_ACTION_ATTR_SET_DL_SRC: eth = nl_attr_get_unspec(a, ETH_ADDR_LEN); ds_put_format(ds, "set_dl_src("ETH_ADDR_FMT")", ETH_ADDR_ARGS(eth)); break; case OVS_ACTION_ATTR_SET_DL_DST: eth = nl_attr_get_unspec(a, ETH_ADDR_LEN); ds_put_format(ds, "set_dl_dst("ETH_ADDR_FMT")", ETH_ADDR_ARGS(eth)); break; case OVS_ACTION_ATTR_SET_NW_SRC: ip = nl_attr_get_be32(a); ds_put_format(ds, "set_nw_src("IP_FMT")", IP_ARGS(&ip)); break; case OVS_ACTION_ATTR_SET_NW_DST: ip = nl_attr_get_be32(a); ds_put_format(ds, "set_nw_dst("IP_FMT")", IP_ARGS(&ip)); break; case OVS_ACTION_ATTR_SET_NW_TOS: ds_put_format(ds, "set_nw_tos(%"PRIu8")", nl_attr_get_u8(a)); break; case OVS_ACTION_ATTR_SET_TP_SRC: ds_put_format(ds, "set_tp_src(%"PRIu16")", ntohs(nl_attr_get_be16(a))); break; case OVS_ACTION_ATTR_SET_TP_DST: ds_put_format(ds, "set_tp_dst(%"PRIu16")", ntohs(nl_attr_get_be16(a))); break; case OVS_ACTION_ATTR_SET_PRIORITY: ds_put_format(ds, "set_priority(%#"PRIx32")", nl_attr_get_u32(a)); break; case OVS_ACTION_ATTR_POP_PRIORITY: ds_put_cstr(ds, "pop_priority"); break; default: format_generic_odp_action(ds, a); break; } }
int main(int argc OVS_UNUSED, char *argv[]) { uint64_t buf_stub[4096 / 64]; struct nl_sock *sock; struct ofpbuf buf; int error; set_program_name(argv[0]); vlog_set_levels(NULL, VLF_ANY_FACILITY, VLL_DBG); error = nl_sock_create(NETLINK_ROUTE, &sock); if (error) { ovs_fatal(error, "could not create rtnetlink socket"); } error = nl_sock_join_mcgroup(sock, RTNLGRP_LINK); if (error) { ovs_fatal(error, "could not join RTNLGRP_LINK multicast group"); } ofpbuf_use_stub(&buf, buf_stub, sizeof buf_stub); for (;;) { error = nl_sock_recv(sock, &buf, false); if (error == EAGAIN) { /* Nothing to do. */ } else if (error == ENOBUFS) { ovs_error(0, "network monitor socket overflowed"); } else if (error) { ovs_fatal(error, "error on network monitor socket"); } else { struct iff_flag { unsigned int flag; const char *name; }; static const struct iff_flag flags[] = { { IFF_UP, "UP", }, { IFF_BROADCAST, "BROADCAST", }, #ifndef _WIN32 { IFF_DEBUG, "DEBUG", }, #endif { IFF_LOOPBACK, "LOOPBACK", }, #ifndef _WIN32 { IFF_POINTOPOINT, "POINTOPOINT", }, { IFF_NOTRAILERS, "NOTRAILERS", }, #endif { IFF_RUNNING, "RUNNING", }, #ifndef _WIN32 { IFF_NOARP, "NOARP", }, #endif { IFF_PROMISC, "PROMISC", }, #ifndef _WIN32 { IFF_ALLMULTI, "ALLMULTI", }, { IFF_MASTER, "MASTER", }, { IFF_SLAVE, "SLAVE", }, #endif { IFF_MULTICAST, "MULTICAST", }, #ifndef _WIN32 { IFF_PORTSEL, "PORTSEL", }, { IFF_AUTOMEDIA, "AUTOMEDIA", }, { IFF_DYNAMIC, "DYNAMIC", }, #endif }; struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)]; struct nlmsghdr *nlh; struct ifinfomsg *iim; int i; nlh = ofpbuf_at(&buf, 0, NLMSG_HDRLEN); iim = ofpbuf_at(&buf, NLMSG_HDRLEN, sizeof *iim); if (!iim) { ovs_error(0, "received bad rtnl message (no ifinfomsg)"); continue; } if (!nl_policy_parse(&buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg), rtnlgrp_link_policy, attrs, ARRAY_SIZE(rtnlgrp_link_policy))) { ovs_error(0, "received bad rtnl message (policy)"); continue; } printf("netdev %s changed (%s):\n", nl_attr_get_string(attrs[IFLA_IFNAME]), (nlh->nlmsg_type == RTM_NEWLINK ? "RTM_NEWLINK" #ifndef _WIN32 : nlh->nlmsg_type == RTM_DELLINK ? "RTM_DELLINK" #endif : nlh->nlmsg_type == RTM_GETLINK ? "RTM_GETLINK" #ifndef _WIN32 : nlh->nlmsg_type == RTM_SETLINK ? "RTM_SETLINK" #endif : "other")); printf("\tflags:"); for (i = 0; i < ARRAY_SIZE(flags); i++) { if (iim->ifi_flags & flags[i].flag) { printf(" %s", flags[i].name); } } printf("\n"); if (attrs[IFLA_MASTER]) { uint32_t idx = nl_attr_get_u32(attrs[IFLA_MASTER]); char ifname[IFNAMSIZ]; #ifndef _WIN32 if (!if_indextoname(idx, ifname)) { strcpy(ifname, "unknown"); } #endif printf("\tmaster=%"PRIu32" (%s)\n", idx, ifname); } } nl_sock_wait(sock, POLLIN); poll_block(); } }