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 (at) 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 27 static struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { 28 [TCA_MIRRED_PARMS] = { .minlen = sizeof(struct tc_mirred) }, 29 }; 30 31 static 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 48 static void mirred_free_data(struct rtnl_tc *tc, void *data) 49 { 50 } 51 52 static 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 60 static 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 96 static void mirred_dump_details(struct rtnl_tc *tc, void *data, 97 struct nl_dump_params *p) 98 { 99 } 100 101 static 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 112 static 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 122 nla_put_failure: 123 return -NLE_NOMEM; 124 } 125 126 /** 127 * @name Attribute Modifications 128 * @{ 129 */ 130 131 int 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 154 int 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 163 int 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 174 uint32_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 183 int 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 206 int 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 217 static 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 232 static void __init mirred_init(void) 233 { 234 rtnl_tc_register(&mirred_ops); 235 } 236 237 static void __exit mirred_exit(void) 238 { 239 rtnl_tc_unregister(&mirred_ops); 240 } 241 242 /** @} */ 243