1/* 2 * lib/route/cls/mirred.c mirred action 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2013 Cong Wang <xiyou.wangcong@gmail.com> 10 */ 11 12/** 13 * @ingroup act 14 * @defgroup act_mirred Mirror and Redirect 15 * 16 * @{ 17 */ 18 19#include <netlink-private/netlink.h> 20#include <netlink-private/tc.h> 21#include <netlink/netlink.h> 22#include <netlink/attr.h> 23#include <netlink/utils.h> 24#include <netlink-private/route/tc-api.h> 25#include <netlink/route/act/mirred.h> 26 27static struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { 28 [TCA_MIRRED_PARMS] = { .minlen = sizeof(struct tc_mirred) }, 29}; 30 31static int mirred_msg_parser(struct rtnl_tc *tc, void *data) 32{ 33 struct rtnl_mirred *u = data; 34 struct nlattr *tb[TCA_MIRRED_MAX + 1]; 35 int err; 36 37 err = tca_parse(tb, TCA_MIRRED_MAX, tc, mirred_policy); 38 if (err < 0) 39 return err; 40 41 if (!tb[TCA_MIRRED_PARMS]) 42 return -NLE_MISSING_ATTR; 43 44 nla_memcpy(&u->m_parm, tb[TCA_MIRRED_PARMS], sizeof(u->m_parm)); 45 return 0; 46} 47 48static void mirred_free_data(struct rtnl_tc *tc, void *data) 49{ 50} 51 52static int mirred_clone(void *_dst, void *_src) 53{ 54 struct rtnl_mirred *dst = _dst, *src = _src; 55 56 memcpy(&dst->m_parm, &src->m_parm, sizeof(src->m_parm)); 57 return 0; 58} 59 60static void mirred_dump_line(struct rtnl_tc *tc, void *data, 61 struct nl_dump_params *p) 62{ 63 struct rtnl_mirred *u = data; 64 if (!u) 65 return; 66 67 nl_dump(p, " index %u", u->m_parm.ifindex); 68 69 if (u->m_parm.eaction == TCA_EGRESS_MIRROR) 70 nl_dump(p, " egress mirror"); 71 else if (u->m_parm.eaction == TCA_EGRESS_REDIR) 72 nl_dump(p, " egress redirect"); 73 74 switch(u->m_parm.action) { 75 case TC_ACT_UNSPEC: 76 nl_dump(p, " unspecified"); 77 break; 78 case TC_ACT_PIPE: 79 nl_dump(p, " pipe"); 80 break; 81 case TC_ACT_STOLEN: 82 nl_dump(p, " stolen"); 83 break; 84 case TC_ACT_SHOT: 85 nl_dump(p, " shot"); 86 break; 87 case TC_ACT_QUEUED: 88 nl_dump(p, " queued"); 89 break; 90 case TC_ACT_REPEAT: 91 nl_dump(p, " repeat"); 92 break; 93 } 94} 95 96static void mirred_dump_details(struct rtnl_tc *tc, void *data, 97 struct nl_dump_params *p) 98{ 99} 100 101static void mirred_dump_stats(struct rtnl_tc *tc, void *data, 102 struct nl_dump_params *p) 103{ 104 struct rtnl_mirred *u = data; 105 106 if (!u) 107 return; 108 /* TODO */ 109} 110 111 112static int mirred_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) 113{ 114 struct rtnl_mirred *u = data; 115 116 if (!u) 117 return 0; 118 119 NLA_PUT(msg, TCA_MIRRED_PARMS, sizeof(u->m_parm), &u->m_parm); 120 return 0; 121 122nla_put_failure: 123 return -NLE_NOMEM; 124} 125 126/** 127 * @name Attribute Modifications 128 * @{ 129 */ 130 131int rtnl_mirred_set_action(struct rtnl_act *act, int action) 132{ 133 struct rtnl_mirred *u; 134 135 if (!(u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act)))) 136 return -NLE_NOMEM; 137 138 if (action > TCA_INGRESS_MIRROR || action < TCA_EGRESS_REDIR) 139 return -NLE_INVAL; 140 141 switch (action) { 142 case TCA_EGRESS_MIRROR: 143 case TCA_EGRESS_REDIR: 144 u->m_parm.eaction = action; 145 break; 146 case TCA_INGRESS_REDIR: 147 case TCA_INGRESS_MIRROR: 148 default: 149 return NLE_OPNOTSUPP; 150 } 151 return 0; 152} 153 154int rtnl_mirred_get_action(struct rtnl_act *act) 155{ 156 struct rtnl_mirred *u; 157 158 if (!(u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act)))) 159 return -NLE_NOMEM; 160 return u->m_parm.eaction; 161} 162 163int rtnl_mirred_set_ifindex(struct rtnl_act *act, uint32_t ifindex) 164{ 165 struct rtnl_mirred *u; 166 167 if (!(u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act)))) 168 return -NLE_NOMEM; 169 170 u->m_parm.ifindex = ifindex; 171 return 0; 172} 173 174uint32_t rtnl_mirred_get_ifindex(struct rtnl_act *act) 175{ 176 struct rtnl_mirred *u; 177 178 if ((u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act)))) 179 return u->m_parm.ifindex; 180 return 0; 181} 182 183int rtnl_mirred_set_policy(struct rtnl_act *act, int policy) 184{ 185 struct rtnl_mirred *u; 186 187 if (!(u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act)))) 188 return -NLE_NOMEM; 189 190 if (policy > TC_ACT_REPEAT || policy < TC_ACT_OK) 191 return -NLE_INVAL; 192 193 switch (u->m_parm.eaction) { 194 case TCA_EGRESS_MIRROR: 195 case TCA_EGRESS_REDIR: 196 u->m_parm.action = policy; 197 break; 198 case TCA_INGRESS_REDIR: 199 case TCA_INGRESS_MIRROR: 200 default: 201 return NLE_OPNOTSUPP; 202 } 203 return 0; 204} 205 206int rtnl_mirred_get_policy(struct rtnl_act *act) 207{ 208 struct rtnl_mirred *u; 209 210 if (!(u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act)))) 211 return -NLE_NOMEM; 212 return u->m_parm.action; 213} 214 215/** @} */ 216 217static struct rtnl_tc_ops mirred_ops = { 218 .to_kind = "mirred", 219 .to_type = RTNL_TC_TYPE_ACT, 220 .to_size = sizeof(struct rtnl_mirred), 221 .to_msg_parser = mirred_msg_parser, 222 .to_free_data = mirred_free_data, 223 .to_clone = mirred_clone, 224 .to_msg_fill = mirred_msg_fill, 225 .to_dump = { 226 [NL_DUMP_LINE] = mirred_dump_line, 227 [NL_DUMP_DETAILS] = mirred_dump_details, 228 [NL_DUMP_STATS] = mirred_dump_stats, 229 }, 230}; 231 232static void __init mirred_init(void) 233{ 234 rtnl_tc_register(&mirred_ops); 235} 236 237static void __exit mirred_exit(void) 238{ 239 rtnl_tc_unregister(&mirred_ops); 240} 241 242/** @} */ 243