/* Receive the next 'entry' from the conntrack netlink dump with 'state'. * Returns 'EOF' when no more entries are available, 0 otherwise. 'entry' may * be uninitilized memory on entry, and must be uninitialized with * ct_dpif_entry_uninit() afterwards by the caller. In case the same 'entry' is * passed to this function again, the entry must also be uninitialized before * the next call. */ int nl_ct_dump_next(struct nl_ct_dump_state *state, struct ct_dpif_entry *entry) { struct ofpbuf buf; memset(entry, 0, sizeof *entry); for (;;) { struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)]; enum nl_ct_event_type type; uint8_t nfgen_family; if (!nl_dump_next(&state->dump, &buf, &state->buf)) { return EOF; } if (!nl_ct_parse_header_policy(&buf, &type, &nfgen_family, attrs)) { continue; }; if (state->filter_zone) { uint16_t entry_zone = attrs[CTA_ZONE] ? ntohs(nl_attr_get_be16(attrs[CTA_ZONE])) : 0; if (entry_zone != state->zone) { continue; } } if (nl_ct_attrs_to_ct_dpif_entry(entry, attrs, nfgen_family)) { break; } ct_dpif_entry_uninit(entry); memset(entry, 0, sizeof *entry); /* Ignore the failed entry and get the next one. */ } ofpbuf_uninit(&buf); return 0; }
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 nl_ct_flush_zone(uint16_t flush_zone) { /* Apparently, there's no netlink interface to flush a specific zone. * This code dumps every connection, checks the zone and eventually * delete the entry. * * This is race-prone, but it is better than using shell scripts. */ struct nl_dump dump; struct ofpbuf buf, reply, delete; ofpbuf_init(&buf, NL_DUMP_BUFSIZE); ofpbuf_init(&delete, NL_DUMP_BUFSIZE); nl_msg_put_nfgenmsg(&buf, 0, AF_UNSPEC, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET, NLM_F_REQUEST); nl_dump_start(&dump, NETLINK_NETFILTER, &buf); ofpbuf_clear(&buf); for (;;) { struct nlattr *attrs[ARRAY_SIZE(nfnlgrp_conntrack_policy)]; enum nl_ct_event_type event_type; uint8_t nfgen_family; uint16_t zone = 0; if (!nl_dump_next(&dump, &reply, &buf)) { break; } if (!nl_ct_parse_header_policy(&reply, &event_type, &nfgen_family, attrs)) { continue; }; if (attrs[CTA_ZONE]) { zone = ntohs(nl_attr_get_be16(attrs[CTA_ZONE])); } if (zone != flush_zone) { /* The entry is not in the zone we're flushing. */ continue; } nl_msg_put_nfgenmsg(&delete, 0, nfgen_family, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST); nl_msg_put_be16(&delete, CTA_ZONE, htons(zone)); nl_msg_put_unspec(&delete, CTA_TUPLE_ORIG, attrs[CTA_TUPLE_ORIG] + 1, attrs[CTA_TUPLE_ORIG]->nla_len - NLA_HDRLEN); nl_msg_put_unspec(&delete, CTA_ID, attrs[CTA_ID] + 1, attrs[CTA_ID]->nla_len - NLA_HDRLEN); nl_transact(NETLINK_NETFILTER, &delete, NULL); ofpbuf_clear(&delete); } nl_dump_done(&dump); ofpbuf_uninit(&delete); ofpbuf_uninit(&buf); /* Expectations are flushed automatically, because they do not * have a master connection anymore */ return 0; }